Merge "msm: vidc: Map rate control vbr_vfr to vbr_cfr"
diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt b/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt
index c3c8212..cc4c3cc 100644
--- a/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt
+++ b/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt
@@ -233,8 +233,6 @@
configuration registers for the Performance cluster.
The array must contain exactly three elements.
- corresponding CPRh device.
-
- qcom,perfcl-apcs-mem-acc-threshold-voltage
Usage: optional
Value type: <u32>
@@ -245,6 +243,27 @@
the MEM ACC threshold voltage specified for the
corresponding CPRh device.
+- qcom,l3-memacc-level-vc-binX
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: Array which defines the NOM and TURBO VCs for the L3 clock
+ on that BIN part.
+ The array must contain exactly two elements.
+
+- qcom,pwrcl-memacc-level-vc-binX
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: Array which defines the NOM and TURBO VCs for the Power
+ cluster clock on that BIN part.
+ The array must contain exactly two elements.
+
+- qcom,perfcl-memacc-level-vc-binX
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: Array which defines the NOM and TURBO VCs for the
+ Performance cluster clock on that BIN part.
+ The array must contain exactly two elements.
+
- qcom,apcs-cbc-addr
Usage: required
Value type: <prop-encoded-array>
@@ -483,6 +502,18 @@
< 1881600000 0x404c1462 0x00004e4e 0x2 21 >,
< 1958400000 0x404c1566 0x00005252 0x3 22 >;
+ qcom,l3-memacc-level-vc-bin0 = <7 63>;
+ qcom,l3-memacc-level-vc-bin1 = <7 9>;
+ qcom,l3-memacc-level-vc-bin2 = <7 9>;
+
+ qcom,pwrcl-memacc-level-vc-bin0 = <12 63>;
+ qcom,pwrcl-memacc-level-vc-bin1 = <12 17>;
+ qcom,pwrcl-memacc-level-vc-bin2 = <12 17>;
+
+ qcom,perfcl-memacc-level-vc-bin0 = <12 18>;
+ qcom,perfcl-memacc-level-vc-bin1 = <12 18>;
+ qcom,perfcl-memacc-level-vc-bin2 = <12 18>;
+
qcom,up-timer =
<1000 1000 1000>;
qcom,down-timer =
diff --git a/Documentation/devicetree/bindings/arm/msm/qsee_ipc_irq_bridge.txt b/Documentation/devicetree/bindings/arm/msm/qsee_ipc_irq_bridge.txt
new file mode 100644
index 0000000..442ad52
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/qsee_ipc_irq_bridge.txt
@@ -0,0 +1,30 @@
+Qualcomm Technologies, Inc. Secure Execution Environment IPC Interrupt Bridge
+
+[Root level node]
+Required properties:
+-compatible : should be "qcom,qsee-ipc-irq-bridge";
+
+[Second level nodes]
+qcom,qsee-ipc-irq-subsystem
+Required properties:
+-qcom,dev-name: the bridge device name
+-interrupt: IPC interrupt line from remote subsystem to QSEE
+-label : The name of this subsystem.
+
+Required properties if interrupt type is IRQ_TYPE_LEVEL_HIGH[4]:
+-qcom,rx-irq-clr : the register to clear the level triggered rx interrupt
+-qcom,rx-irq-clr-mask : the bitmask to clear the rx interrupt
+
+Example:
+
+ qcom,qsee_ipc_irq_bridge {
+ compatible = "qcom,qsee-ipc-irq-bridge";
+
+ qcom,qsee-ipc-irq-spss {
+ qcom,rx-irq-clr = <0x1d08008 0x4>;
+ qcom,rx-irq-clr-mask = <0x2>;
+ qcom,dev-name = "qsee_ipc_irq_spss";
+ interrupts = <0 349 4>;
+ label = "spss";
+ };
+ };
diff --git a/Documentation/devicetree/bindings/clock/qcom,aop-qmp.txt b/Documentation/devicetree/bindings/clock/qcom,aop-qmp.txt
index 231b8a3..37c48ad 100644
--- a/Documentation/devicetree/bindings/clock/qcom,aop-qmp.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,aop-qmp.txt
@@ -2,7 +2,7 @@
------------------------------------------------------------------------
Required properties :
-- compatible : must be "qcom,aop-qmp-clk"
+- compatible : must be "qcom,aop-qmp-clk-v1" or "qcom,aop-qmp-clk-v2".
- #clock-cells : must contain 1
- mboxes : list of QMP mailbox phandle and channel identifier tuples.
- mbox-names: List of identifier strings for each mailbox channel.
@@ -10,7 +10,7 @@
Example :
clock_qdss: qcom,aopclk {
- compatible = "qcom,aop-qmp-clk";
+ compatible = "qcom,aop-qmp-clk-v1";
#clock-cells = <1>;
mboxes = <&qmp_aop 0>;
mbox-names = "qdss_clk";
diff --git a/Documentation/devicetree/bindings/clock/qcom,gpucc.txt b/Documentation/devicetree/bindings/clock/qcom,gpucc.txt
index f214c58..12676b7 100644
--- a/Documentation/devicetree/bindings/clock/qcom,gpucc.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,gpucc.txt
@@ -4,7 +4,9 @@
Required properties :
- compatible : shall contain only one of the following:
"qcom,gpucc-sdm845",
- "qcom,gfxcc-sdm845"
+ "qcom,gpucc-sdm845-v2",
+ "qcom,gfxcc-sdm845",
+ "qcom,gfxcc-sdm845-v2"
- reg : shall contain base register offset and size.
- #clock-cells : shall contain 1.
diff --git a/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt
index cbe8378..32c31af 100644
--- a/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt
@@ -401,6 +401,24 @@
String that specifies the ctrl state for reading the panel status.
"dsi_lp_mode" = DSI low power mode
"dsi_hs_mode" = DSI high speed mode
+- qcom,mdss-dsi-lp1-command: An optional byte stream to request low
+ power mode on a panel
+- qcom,mdss-dsi-lp1-command-mode: String that specifies the ctrl state for
+ setting the panel power mode.
+ "dsi_lp_mode" = DSI low power mode
+ "dsi_hs_mode" = DSI high speed mode
+- qcom,mdss-dsi-lp2-command: An optional byte stream to request ultra
+ low power mode on a panel
+- qcom,mdss-dsi-lp2-command-mode: String that specifies the ctrl state for
+ setting the panel power mode.
+ "dsi_lp_mode" = DSI low power mode
+ "dsi_hs_mode" = DSI high speed mode
+- qcom,mdss-dsi-nolp-command: An optional byte stream to disable low
+ power and ultra low power panel modes
+- qcom,mdss-dsi-nolp-command-mode: String that specifies the ctrl state for
+ setting the panel power mode.
+ "dsi_lp_mode" = DSI low power mode
+ "dsi_hs_mode" = DSI high speed mode
- qcom,mdss-dsi-panel-status-check-mode:Specifies the panel status check method for ESD recovery.
"bta_check" = Uses BTA to check the panel status
"reg_read" = Reads panel status register to check the panel status
diff --git a/Documentation/devicetree/bindings/msm_hdcp/msm_hdcp.txt b/Documentation/devicetree/bindings/msm_hdcp/msm_hdcp.txt
new file mode 100644
index 0000000..8d5f55d
--- /dev/null
+++ b/Documentation/devicetree/bindings/msm_hdcp/msm_hdcp.txt
@@ -0,0 +1,14 @@
+MSM HDCP driver
+
+Standalone driver managing HDCP related communications
+between TZ and HLOS for MSM chipset.
+
+Required properties:
+
+compatible = "qcom,msm-hdcp";
+
+Example:
+
+qcom_msmhdcp: qcom,msm_hdcp {
+ compatible = "qcom,msm-hdcp";
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
index f2a4063..45a0fdc 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
@@ -294,6 +294,11 @@
};
};
+ qcom,ipa_fws {
+ compatible = "qcom,pil-tz-generic";
+ qcom,pas-id = <0xf>;
+ qcom,firmware-name = "ipa_fws";
+ };
};
#include "sdxpoorwills-regulator.dtsi"
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 441063f..99d1fe7 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -50,6 +50,8 @@
pgprot_t prot;
const void *caller;
bool want_vaddr;
+ bool skip_cpu_sync;
+ bool skip_zeroing;
int coherent_flag;
};
@@ -276,7 +278,8 @@
return mask;
}
-static void __dma_clear_buffer(struct page *page, size_t size, int coherent_flag)
+static void __dma_clear_buffer(struct page *page, size_t size,
+ bool skip_zeroing, int coherent_flag)
{
/*
* Ensure that the allocated pages are zeroed, and that any data
@@ -287,7 +290,8 @@
phys_addr_t end = base + size;
while (size > 0) {
void *ptr = kmap_atomic(page);
- memset(ptr, 0, PAGE_SIZE);
+ if (!skip_zeroing)
+ memset(ptr, 0, PAGE_SIZE);
if (coherent_flag != COHERENT)
dmac_flush_range(ptr, ptr + PAGE_SIZE);
kunmap_atomic(ptr);
@@ -298,7 +302,8 @@
outer_flush_range(base, end);
} else {
void *ptr = page_address(page);
- memset(ptr, 0, size);
+ if (!skip_zeroing)
+ memset(ptr, 0, size);
if (coherent_flag != COHERENT) {
dmac_flush_range(ptr, ptr + size);
outer_flush_range(__pa(ptr), __pa(ptr) + size);
@@ -327,7 +332,7 @@
for (p = page + (size >> PAGE_SHIFT), e = page + (1 << order); p < e; p++)
__free_page(p);
- __dma_clear_buffer(page, size, coherent_flag);
+ __dma_clear_buffer(page, size, false, coherent_flag);
return page;
}
@@ -350,6 +355,7 @@
static void *__alloc_from_contiguous(struct device *dev, size_t size,
pgprot_t prot, struct page **ret_page,
const void *caller, bool want_vaddr,
+ bool skip_cpu_sync, bool skip_zeroing,
int coherent_flag);
static void *__alloc_remap_buffer(struct device *dev, size_t size, gfp_t gfp,
@@ -369,10 +375,10 @@
prot, caller);
}
-static void __dma_free_remap(void *cpu_addr, size_t size)
+static void __dma_free_remap(void *cpu_addr, size_t size, bool no_warn)
{
dma_common_free_remap(cpu_addr, size,
- VM_ARM_DMA_CONSISTENT | VM_USERMAP, false);
+ VM_ARM_DMA_CONSISTENT | VM_USERMAP, no_warn);
}
#define DEFAULT_DMA_COHERENT_POOL_SIZE SZ_256K
@@ -421,7 +427,8 @@
*/
if (dev_get_cma_area(NULL))
ptr = __alloc_from_contiguous(NULL, atomic_pool_size, prot,
- &page, atomic_pool_init, true, NORMAL);
+ &page, atomic_pool_init, true, false,
+ false, NORMAL);
else
ptr = __alloc_remap_buffer(NULL, atomic_pool_size, gfp, prot,
&page, atomic_pool_init, true);
@@ -520,21 +527,39 @@
return 0;
}
-static void __dma_remap(struct page *page, size_t size, pgprot_t prot)
+static int __dma_clear_pte(pte_t *pte, pgtable_t token, unsigned long addr,
+ void *data)
+{
+ pte_clear(&init_mm, addr, pte);
+ return 0;
+}
+
+static void __dma_remap(struct page *page, size_t size, pgprot_t prot,
+ bool want_vaddr)
{
unsigned long start = (unsigned long) page_address(page);
unsigned end = start + size;
+ int (*func)(pte_t *pte, pgtable_t token, unsigned long addr,
+ void *data);
- apply_to_page_range(&init_mm, start, size, __dma_update_pte, &prot);
+ if (!want_vaddr)
+ func = __dma_clear_pte;
+ else
+ func = __dma_update_pte;
+
+ apply_to_page_range(&init_mm, start, size, func, &prot);
+ mb(); /*Ensure pte's are updated */
flush_tlb_kernel_range(start, end);
}
+
+#define NO_KERNEL_MAPPING_DUMMY 0x2222
static void *__alloc_remap_buffer(struct device *dev, size_t size, gfp_t gfp,
pgprot_t prot, struct page **ret_page,
const void *caller, bool want_vaddr)
{
struct page *page;
- void *ptr = NULL;
+ void *ptr = (void *)NO_KERNEL_MAPPING_DUMMY;
/*
* __alloc_remap_buffer is only called when the device is
* non-coherent
@@ -595,6 +620,7 @@
static void *__alloc_from_contiguous(struct device *dev, size_t size,
pgprot_t prot, struct page **ret_page,
const void *caller, bool want_vaddr,
+ bool skip_cpu_sync, bool skip_zeroing,
int coherent_flag)
{
unsigned long order = get_order(size);
@@ -606,23 +632,37 @@
if (!page)
return NULL;
- __dma_clear_buffer(page, size, coherent_flag);
-
- if (!want_vaddr)
- goto out;
+ /*
+ * skip completely if we neither need to zero nor sync.
+ */
+ if (!(skip_cpu_sync && skip_zeroing))
+ __dma_clear_buffer(page, size, skip_zeroing, coherent_flag);
if (PageHighMem(page)) {
- ptr = __dma_alloc_remap(page, size, GFP_KERNEL, prot, caller);
- if (!ptr) {
- dma_release_from_contiguous(dev, page, count);
- return NULL;
+ if (!want_vaddr) {
+ /*
+ * Something non-NULL needs to be returned here. Give
+ * back a dummy address that is unmapped to catch
+ * clients trying to use the address incorrectly
+ */
+ ptr = (void *)NO_KERNEL_MAPPING_DUMMY;
+
+ /* also flush out the stale highmem mappings */
+ kmap_flush_unused();
+ kmap_atomic_flush_unused();
+ } else {
+ ptr = __dma_alloc_remap(page, size, GFP_KERNEL, prot,
+ caller);
+ if (!ptr) {
+ dma_release_from_contiguous(dev, page, count);
+ return NULL;
+ }
}
} else {
- __dma_remap(page, size, prot);
+ __dma_remap(page, size, prot, want_vaddr);
ptr = page_address(page);
}
- out:
*ret_page = page;
return ptr;
}
@@ -630,12 +670,10 @@
static void __free_from_contiguous(struct device *dev, struct page *page,
void *cpu_addr, size_t size, bool want_vaddr)
{
- if (want_vaddr) {
- if (PageHighMem(page))
- __dma_free_remap(cpu_addr, size);
- else
- __dma_remap(page, size, PAGE_KERNEL);
- }
+ if (PageHighMem(page))
+ __dma_free_remap(cpu_addr, size, true);
+ else
+ __dma_remap(page, size, PAGE_KERNEL, true);
dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT);
}
@@ -656,10 +694,11 @@
#define __get_dma_pgprot(attrs, prot) __pgprot(0)
#define __alloc_remap_buffer(dev, size, gfp, prot, ret, c, wv) NULL
#define __alloc_from_pool(size, ret_page) NULL
-#define __alloc_from_contiguous(dev, size, prot, ret, c, wv, coherent_flag) NULL
+#define __alloc_from_contiguous(dev, size, prot, ret, c, \
+ wv, scs, sz, coherent_flag) NULL
#define __free_from_pool(cpu_addr, size) do { } while (0)
#define __free_from_contiguous(dev, page, cpu_addr, size, wv) do { } while (0)
-#define __dma_free_remap(cpu_addr, size) do { } while (0)
+#define __dma_free_remap(cpu_addr, size, w) do { } while (0)
#endif /* CONFIG_MMU */
@@ -698,7 +737,8 @@
{
return __alloc_from_contiguous(args->dev, args->size, args->prot,
ret_page, args->caller,
- args->want_vaddr, args->coherent_flag);
+ args->want_vaddr, args->skip_cpu_sync,
+ args->skip_zeroing, args->coherent_flag);
}
static void cma_allocator_free(struct arm_dma_free_args *args)
@@ -739,7 +779,7 @@
static void remap_allocator_free(struct arm_dma_free_args *args)
{
if (args->want_vaddr)
- __dma_free_remap(args->cpu_addr, args->size);
+ __dma_free_remap(args->cpu_addr, args->size, false);
__dma_free_buffer(args->page, args->size);
}
@@ -765,6 +805,8 @@
.prot = prot,
.caller = caller,
.want_vaddr = ((attrs & DMA_ATTR_NO_KERNEL_MAPPING) == 0),
+ .skip_cpu_sync = (attrs & DMA_ATTR_SKIP_CPU_SYNC),
+ .skip_zeroing = (attrs & DMA_ATTR_SKIP_ZEROING),
.coherent_flag = is_coherent ? COHERENT : NORMAL,
};
@@ -826,7 +868,7 @@
kfree(buf);
}
- return args.want_vaddr ? addr : page;
+ return addr;
}
/*
@@ -1298,7 +1340,7 @@
if (!page)
goto error;
- __dma_clear_buffer(page, size, coherent_flag);
+ __dma_clear_buffer(page, size, false, coherent_flag);
for (i = 0; i < count; i++)
pages[i] = page + i;
@@ -1348,7 +1390,8 @@
pages[i + j] = pages[i] + j;
}
- __dma_clear_buffer(pages[i], PAGE_SIZE << order, coherent_flag);
+ __dma_clear_buffer(pages[i], PAGE_SIZE << order,
+ false, coherent_flag);
i += 1 << order;
count -= 1 << order;
}
@@ -2287,12 +2330,16 @@
struct dma_iommu_mapping *mapping)
{
int err;
+ int s1_bypass = 0;
err = __arm_iommu_attach_device(dev, mapping);
if (err)
return err;
- set_dma_ops(dev, &iommu_ops);
+ iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_S1_BYPASS,
+ &s1_bypass);
+ if (!s1_bypass)
+ set_dma_ops(dev, &iommu_ops);
return 0;
}
EXPORT_SYMBOL_GPL(arm_iommu_attach_device);
@@ -2326,8 +2373,21 @@
*/
void arm_iommu_detach_device(struct device *dev)
{
+ struct dma_iommu_mapping *mapping;
+ int s1_bypass = 0;
+
+ mapping = to_dma_iommu_mapping(dev);
+ if (!mapping) {
+ dev_warn(dev, "Not attached\n");
+ return;
+ }
+
__arm_iommu_detach_device(dev);
- set_dma_ops(dev, NULL);
+
+ iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_S1_BYPASS,
+ &s1_bypass);
+ if (!s1_bypass)
+ set_dma_ops(dev, NULL);
}
EXPORT_SYMBOL_GPL(arm_iommu_detach_device);
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index dae2f9f..f96fba6 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -116,6 +116,8 @@
select PINCTRL
select SOC_BUS
select PM_OPP
+ select MFD_CORE
+ select SND_SOC_COMPRESS
help
This enables support for the ARMv8 based Qualcomm chipsets.
diff --git a/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
index b0c436f..0a8c49f 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
@@ -15,331 +15,6 @@
/* Stub regulators */
/ {
- pm660_s4: regulator-pm660-s4 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_s4";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <2040000>;
- regulator-max-microvolt = <2040000>;
- };
-
- /* pm660 S5 - VDD_MODEM supply */
- pm660_s5_level: regulator-pm660-s5 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_s5_level";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
- regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
- };
-
- pm660_s6: regulator-pm660-s6 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_s6";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <1352000>;
- regulator-max-microvolt = <1352000>;
- };
-
- /* pm660l S1 - VDD_MX supply */
- pm660l_s1_level: regulator-pm660l-s1 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660l_s1_level";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
- regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
- };
-
- pm660l_s1_floor_level: regulator-pm660l-s1-floor-level {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660l_s1_floor_level";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
- regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
- };
-
- pm660l_s1_level_ao: regulator-pm660l-s1-level-ao {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660l_s1_level_ao";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
- regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
- };
-
- /* pm660l S2 - VDD_GFX supply */
- pm660l_s2_level: regulator-pm660l-s2 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660l_s2_level";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
- regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
- };
-
- /* pm660l S3 + S4 - VDD_CX supply */
- pm660l_s3_level: regulator-pm660l-s3-level {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660l_s3_level";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
- regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
- };
-
- pm660l_s3_floor_level: regulator-pm660l-s3-floor-level {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660l_s3_floor_level";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
- regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
- };
-
- pm660l_s3_level_ao: regulator-pm660l-s3-level-ao {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_s3_level_ao";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
- regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
- };
-
- pm660_l1: regulator-pm660-l1 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_l1";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1250000>;
- };
-
- pm660_l2: regulator-pm660-l2 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_l2";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- };
-
- pm660_l3: regulator-pm660-l3 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_l3";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- };
-
- pm660_l5: regulator-pm660-l5 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_l5";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <800000>;
- regulator-max-microvolt = <800000>;
- };
-
- pm660_l6: regulator-pm660-l6 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_l6";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1304000>;
- regulator-max-microvolt = <1304000>;
- };
-
- pm660_l7: regulator-pm660-l7 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_l7";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- };
-
- pm660_l8: regulator-pm660-l8 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_l8";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- pm660_l9: regulator-pm660-l9 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_l9";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- pm660_l10: regulator-pm660-l10 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_l10";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- pm660_l11: regulator-pm660-l11 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_l11";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- pm660_l12: regulator-pm660-l12 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_l12";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- pm660_l13: regulator-pm660-l13 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_l13";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- pm660_l14: regulator-pm660-l14 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_l14";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- pm660_l15: regulator-pm660-l15 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_l15";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <2950000>;
- };
-
- pm660_l16: regulator-pm660-l16 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_l16";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <2700000>;
- regulator-max-microvolt = <2700000>;
- };
-
- pm660_l17: regulator-pm660-l17 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_l17";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <2950000>;
- };
-
- pm660_l19: regulator-pm660-l19 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660_l19";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <3312000>;
- regulator-max-microvolt = <3312000>;
- };
-
- pm660l_l1: regulator-pm660l-l1 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660l_l1";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <880000>;
- regulator-max-microvolt = <900000>;
- };
-
- pm660l_l2: regulator-pm660l-l2 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660l_l2";
- qcom,hpm-min-load = <5000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <2960000>;
- };
-
- pm660l_l3: regulator-pm660l-l3 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660l_l3";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <2850000>;
- regulator-max-microvolt = <3008000>;
- };
-
- pm660l_l4: regulator-pm660l-l4 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660l_l4";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <2960000>;
- regulator-max-microvolt = <2960000>;
- };
-
- pm660l_l5: regulator-pm660l-l5 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660l_l5";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <2960000>;
- regulator-max-microvolt = <2960000>;
- };
-
- pm660l_l6: regulator-pm660l-l6 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660l_l6";
- qcom,hpm-min-load = <5000>;
- regulator-min-microvolt = <3008000>;
- regulator-max-microvolt = <3300000>;
- };
-
- pm660l_l7: regulator-pm660l-l7 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660l_l7";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <3088000>;
- regulator-max-microvolt = <3100000>;
- };
-
- pm660l_l8: regulator-pm660l-l8 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660l_l8";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3312000>;
- };
-
- /* pm660l L9 = VDD_LPI_CX supply */
- pm660l_l9_level: regulator-pm660l-l9-level {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660l_l9_level";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
- regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
- };
-
- pm660l_l9_floor_level: regulator-pm660l-l9-floor-level {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660l_l9_floor_level";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
- regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
- };
-
- /* pm660l L10 = VDD_LPI_MX supply */
- pm660l_l10_level: regulator-pm660l-l10-level {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660l_l10_level";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
- regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
- };
-
- pm660l_l10_floor_level: regulator-pm660l-l10-floor-level {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660l_l10_floor_level";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
- regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
- };
-
- pm660l_bob: regulator-pm660l-bob {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm660l_bob";
- regulator-min-microvolt = <3312000>;
- regulator-max-microvolt = <3312000>;
- };
-
apc0_pwrcl_vreg: regulator-pwrcl {
compatible = "qcom,stub-regulator";
regulator-name = "apc0_pwrcl_corner";
@@ -362,6 +37,598 @@
};
};
+&soc {
+ /* RPMh regulators: */
+ rpmh-regulator-smpa4 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "smpa4";
+ pm660_s4: regulator-pm660-s4 {
+ regulator-name = "pm660_s4";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <2040000>;
+ regulator-max-microvolt = <2040000>;
+ qcom,init-voltage = <2040000>;
+ };
+ };
+
+ /* pm660 S5 - VDD_MODEM supply */
+ rpmh-regulator-modemlvl {
+ compatible = "qcom,rpmh-arc-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "mss.lvl";
+ pm660_s5_level: regulator-pm660-s5 {
+ regulator-name = "pm660_s5_level";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
+ regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
+ };
+ };
+
+ rpmh-regulator-smpa6 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "smpa6";
+ pm660_s6: regulator-pm660-s6 {
+ regulator-name = "pm660_s6";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1352000>;
+ regulator-max-microvolt = <1352000>;
+ qcom,init-voltage = <1352000>;
+ };
+ };
+
+ /* pm660l S1 - VDD_MX supply */
+ rpmh-regulator-mxlvl {
+ compatible = "qcom,rpmh-arc-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "mx.lvl";
+ pm660l_s1_level: regulator-pm660l-s1 {
+ regulator-name = "pm660l_s1_level";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
+ regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
+ };
+
+ pm660l_s1_level_ao: regulator-pm660l-s1-level-ao {
+ regulator-name = "pm660l_s1_level_ao";
+ qcom,set = <RPMH_REGULATOR_SET_ACTIVE>;
+ regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
+ regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
+ };
+ };
+
+ /* pm660l S2 - VDD_GFX supply */
+ rpmh-regulator-gfxlvl {
+ compatible = "qcom,rpmh-arc-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "gfx.lvl";
+ pm660l_s2_level: regulator-pm660l-s2 {
+ regulator-name = "pm660l_s2_level";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt
+ = <RPMH_REGULATOR_LEVEL_MIN_SVS>;
+ regulator-max-microvolt
+ = <RPMH_REGULATOR_LEVEL_MAX>;
+ qcom,init-voltage-level
+ = <RPMH_REGULATOR_LEVEL_MIN_SVS>;
+ };
+ };
+
+ /* pm660l S3 + S4 - VDD_CX supply */
+ rpmh-regulator-cxlvl {
+ compatible = "qcom,rpmh-arc-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "cx.lvl";
+ pm660l_s3_level-parent-supply = <&pm660l_s1_level>;
+ pm660l_s3_level_ao-parent-supply = <&pm660l_s1_level_ao>;
+ pm660l_s3_level: regulator-pm660l-s3-level {
+ regulator-name = "pm660l_s3_level";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
+ regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
+ qcom,min-dropout-voltage-level = <(-1)>;
+ };
+
+ pm660l_s3_level_ao: regulator-pm660l-s3-level-ao {
+ regulator-name = "pm660l_s3_level_ao";
+ qcom,set = <RPMH_REGULATOR_SET_ACTIVE>;
+ regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
+ regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
+ qcom,min-dropout-voltage-level = <(-1)>;
+ };
+ };
+
+ rpmh-regulator-ldoa1 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa1";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l1: regulator-pm660-l1 {
+ regulator-name = "pm660_l1";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1250000>;
+ qcom,init-voltage = <1200000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa2 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa2";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l2: regulator-pm660-l2 {
+ regulator-name = "pm660_l2";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ qcom,init-voltage = <1000000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa3 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa3";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l3: regulator-pm660-l3 {
+ regulator-name = "pm660_l3";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ qcom,init-voltage = <1000000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa5 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa5";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l5: regulator-pm660-l5 {
+ regulator-name = "pm660_l5";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <800000>;
+ qcom,init-voltage = <800000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa6 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa6";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l6: regulator-pm660-l6 {
+ regulator-name = "pm660_l6";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1304000>;
+ regulator-max-microvolt = <1304000>;
+ qcom,init-voltage = <1304000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa7 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa7";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l7: regulator-pm660-l7 {
+ regulator-name = "pm660_l7";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ qcom,init-voltage = <1200000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa8 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa8";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l8: regulator-pm660-l8 {
+ regulator-name = "pm660_l8";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa9 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa9";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l9: regulator-pm660-l9 {
+ regulator-name = "pm660_l9";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa10 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa10";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l10: regulator-pm660-l10 {
+ regulator-name = "pm660_l10";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa11 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa11";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l11: regulator-pm660-l11 {
+ regulator-name = "pm660_l11";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa12 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa12";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l12: regulator-pm660-l12 {
+ regulator-name = "pm660_l12";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa13 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa13";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l13: regulator-pm660-l13 {
+ regulator-name = "pm660_l13";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa14 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa14";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l14: regulator-pm660-l14 {
+ regulator-name = "pm660_l14";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa15 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa15";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l15: regulator-pm660-l15 {
+ regulator-name = "pm660_l15";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ qcom,init-voltage = <1800000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa16 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa16";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l16: regulator-pm660-l16 {
+ regulator-name = "pm660_l16";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <2700000>;
+ regulator-max-microvolt = <2700000>;
+ qcom,init-voltage = <2700000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa17 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa17";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l17: regulator-pm660-l17 {
+ regulator-name = "pm660_l17";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ qcom,init-voltage = <1800000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa19 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa19";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l19: regulator-pm660-l19 {
+ regulator-name = "pm660_l19";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <3312000>;
+ regulator-max-microvolt = <3312000>;
+ qcom,init-voltage = <3312000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldob1 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldob1";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660l_l1: regulator-pm660l-l1 {
+ regulator-name = "pm660l_l1";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <880000>;
+ regulator-max-microvolt = <900000>;
+ qcom,init-voltage = <880000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldob2 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldob2";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660l_l2: regulator-pm660l-l2 {
+ regulator-name = "pm660l_l2";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2960000>;
+ qcom,init-voltage = <1800000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldob3 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldob3";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660l_l3: regulator-pm660l-l3 {
+ regulator-name = "pm660l_l3";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <3008000>;
+ qcom,init-voltage = <2850000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldob4 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldob4";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660l_l4: regulator-pm660l-l4 {
+ regulator-name = "pm660l_l4";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <2960000>;
+ regulator-max-microvolt = <2960000>;
+ qcom,init-voltage = <2960000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldob5 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldob5";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660l_l5: regulator-pm660l-l5 {
+ regulator-name = "pm660l_l5";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <2960000>;
+ regulator-max-microvolt = <2960000>;
+ qcom,init-voltage = <2960000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldob6 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldob6";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660l_l6: regulator-pm660l-l6 {
+ regulator-name = "pm660l_l6";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <3008000>;
+ regulator-max-microvolt = <3300000>;
+ qcom,init-voltage = <3008000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldob7 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldob7";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660l_l7: regulator-pm660l-l7 {
+ regulator-name = "pm660l_l7";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <3088000>;
+ regulator-max-microvolt = <3100000>;
+ qcom,init-voltage = <3088000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldob8 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldob8";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660l_l8: regulator-pm660l-l8 {
+ regulator-name = "pm660l_l8";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3312000>;
+ qcom,init-voltage = <3300000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ /* pm660l L9 = VDD_LPI_CX supply */
+ rpmh-regulator-lcxlvl {
+ compatible = "qcom,rpmh-arc-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "lcx.lvl";
+ pm660l_l9_level: regulator-pm660l-l9-level {
+ regulator-name = "pm660l_l9_level";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
+ regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
+ };
+ };
+
+ /* pm660l L10 = VDD_LPI_MX supply */
+ rpmh-regulator-lmxlvl {
+ compatible = "qcom,rpmh-arc-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "lmx.lvl";
+ pm660l_l10_level: regulator-pm660l-l10-level {
+ regulator-name = "pm660l_l10_level";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
+ regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
+ };
+ };
+
+ rpmh-regulator-bobb1 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "bobb1";
+ pm660l_bob: regulator-pm660l-bob {
+ regulator-name = "pm660l_bob";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <3312000>;
+ regulator-max-microvolt = <3312000>;
+ qcom,init-voltage = <3312000>;
+ };
+ };
+};
+
&pm660_charger {
smb2_vbus: qcom,smb2-vbus {
regulator-name = "smb2-vbus";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp-overlay.dts
index 0006937..a78672d 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp-overlay.dts
@@ -27,7 +27,7 @@
/ {
model = "Qualcomm Technologies, Inc. sdm845 4K Display Panel CDP";
compatible = "qcom,sdm845-cdp", "qcom,sdm845", "qcom,cdp";
- qcom,msm-id = <321 0x0>;
+ qcom,msm-id = <321 0x10000>;
qcom,board-id = <1 1>;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp-overlay.dts
index 2675b96..a776d42 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp-overlay.dts
@@ -27,7 +27,7 @@
/ {
model = "Qualcomm Technologies, Inc. sdm845 4K Display Panel MTP";
compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp";
- qcom,msm-id = <321 0x0>;
+ qcom,msm-id = <321 0x10000>;
qcom,board-id = <8 1>;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd-overlay.dts
index 39c9d37..c6622d4 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd-overlay.dts
@@ -27,6 +27,38 @@
/ {
model = "Qualcomm Technologies, Inc. sdm845 4K Display Panel QRD";
compatible = "qcom,sdm845-qrd", "qcom,sdm845", "qcom,qrd";
- qcom,msm-id = <321 0x0>;
+ qcom,msm-id = <321 0x10000>;
qcom,board-id = <11 1>;
};
+
+&dsi_nt35597_truly_dsc_cmd_display {
+ /delete-property/ qcom,dsi-display-active;
+};
+
+&dsi_sharp_4k_dsc_video {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+ qcom,mdss-dsi-panel-orientation = "180";
+};
+
+&dsi_sharp_4k_dsc_cmd {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+ qcom,mdss-dsi-panel-orientation = "180";
+};
+
+&dsi_sharp_4k_dsc_video_display {
+ qcom,dsi-display-active;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd.dts b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd.dts
index 5951f6d..20f80c9 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd.dts
@@ -22,3 +22,35 @@
compatible = "qcom,sdm845-qrd", "qcom,sdm845", "qcom,qrd";
qcom,board-id = <11 1>;
};
+
+&dsi_nt35597_truly_dsc_cmd_display {
+ /delete-property/ qcom,dsi-display-active;
+};
+
+&dsi_sharp_4k_dsc_video {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+ qcom,mdss-dsi-panel-orientation = "180";
+};
+
+&dsi_sharp_4k_dsc_cmd {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+ qcom,mdss-dsi-panel-orientation = "180";
+};
+
+&dsi_sharp_4k_dsc_video_display {
+ qcom,dsi-display-active;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-cdp-overlay.dts
index efc78e0..7991aad 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-cdp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-cdp-overlay.dts
@@ -26,6 +26,6 @@
/ {
model = "Qualcomm Technologies, Inc. SDM845 v1 CDP";
compatible = "qcom,sdm845-cdp", "qcom,sdm845", "qcom,cdp";
- qcom,msm-id = <321 0x0>;
+ qcom,msm-id = <321 0x10000>;
qcom,board-id = <1 0>;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts
index 45941a1..2d1d9b6 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts
@@ -26,6 +26,6 @@
/ {
model = "Qualcomm Technologies, Inc. SDM845 v1 MTP";
compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp";
- qcom,msm-id = <321 0x0>;
+ qcom,msm-id = <321 0x10000>;
qcom,board-id = <8 0>;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
index 04f67cd..f691740 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
@@ -1400,6 +1400,90 @@
};
};
+ quat_tdm {
+ quat_tdm_sleep: quat_tdm_sleep {
+ mux {
+ pins = "gpio58", "gpio59";
+ function = "qua_mi2s";
+ };
+
+ config {
+ pins = "gpio58", "gpio59";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+
+ quat_tdm_active: quat_tdm_active {
+ mux {
+ pins = "gpio58", "gpio59";
+ function = "qua_mi2s";
+ };
+
+ config {
+ pins = "gpio58", "gpio59";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL */
+ };
+ };
+ };
+
+ quat_tdm_dout {
+ quat_tdm_dout_sleep: quat_tdm_dout_sleep {
+ mux {
+ pins = "gpio61";
+ function = "qua_mi2s";
+ };
+
+ config {
+ pins = "gpio61";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+
+ quat_tdm_dout_active: quat_tdm_dout_active {
+ mux {
+ pins = "gpio61";
+ function = "qua_mi2s";
+ };
+
+ config {
+ pins = "gpio61";
+ drive-strength = <2>; /* 2 mA */
+ bias-disable; /* NO PULL */
+ };
+ };
+ };
+
+ quat_tdm_din {
+ quat_tdm_din_sleep: quat_tdm_din_sleep {
+ mux {
+ pins = "gpio60";
+ function = "qua_mi2s";
+ };
+
+ config {
+ pins = "gpio60";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+
+ quat_tdm_din_active: quat_tdm_din_active {
+ mux {
+ pins = "gpio60";
+ function = "qua_mi2s";
+ };
+
+ config {
+ pins = "gpio60";
+ drive-strength = <2>; /* 2 mA */
+ bias-disable; /* NO PULL */
+ };
+ };
+ };
+
/* QUPv3 South SE mappings */
/* SE 0 pin mappings */
qupv3_se0_i2c_pins: qupv3_se0_i2c_pins {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-qrd-overlay.dts
index 6cead9d..c8136de 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qrd-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-qrd-overlay.dts
@@ -26,6 +26,6 @@
/ {
model = "Qualcomm Technologies, Inc. SDM845 v1 QRD";
compatible = "qcom,sdm845-qrd", "qcom,sdm845", "qcom,qrd";
- qcom,msm-id = <321 0x0>;
+ qcom,msm-id = <321 0x10000>;
qcom,board-id = <11 0>;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
index 6bdc149..9b683cc 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
@@ -185,35 +185,42 @@
qcom,led-strings-list = [01 02];
};
+&pmi8998_haptics {
+ qcom,vmax-mv = <1800>;
+ qcom,wave-play-rate-us = <4347>;
+ qcom,lra-auto-mode;
+ status = "okay";
+};
+
&mdss_mdp {
connectors = <&sde_rscc &sde_wb>;
};
-&dsi_sharp_4k_dsc_video {
+&dsi_nt35597_truly_dsc_cmd {
qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
qcom,mdss-dsi-bl-min-level = <1>;
qcom,mdss-dsi-bl-max-level = <4095>;
- qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,mdss-dsi-mode-sel-gpio-state = "single_port";
qcom,panel-mode-gpio = <&tlmm 52 0>;
qcom,platform-te-gpio = <&tlmm 10 0>;
qcom,platform-reset-gpio = <&tlmm 6 0>;
qcom,mdss-dsi-panel-orientation = "180";
};
-&dsi_sharp_4k_dsc_cmd {
+&dsi_nt35597_truly_dsc_video {
qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
qcom,mdss-dsi-bl-min-level = <1>;
qcom,mdss-dsi-bl-max-level = <4095>;
- qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,mdss-dsi-mode-sel-gpio-state = "single_port";
qcom,panel-mode-gpio = <&tlmm 52 0>;
qcom,platform-te-gpio = <&tlmm 10 0>;
qcom,platform-reset-gpio = <&tlmm 6 0>;
qcom,mdss-dsi-panel-orientation = "180";
};
-&dsi_sharp_4k_dsc_video_display {
+&dsi_nt35597_truly_dsc_cmd_display {
qcom,dsi-display-active;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
index 17adbf4..0618f92 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
@@ -30,7 +30,7 @@
clock-names = "gcc_iface", "gcc_bus", "iface_clk",
"bus_clk", "core_clk", "vsync_clk";
clock-rate = <0 0 0 0 300000000 19200000 0>;
- clock-max-rate = <0 0 0 0 430000000 19200000 0>;
+ clock-max-rate = <0 0 0 0 412500000 19200000 0>;
sde-vdd-supply = <&mdss_core_gdsc>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
index b8aeb87..34f3cb3 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
@@ -434,8 +434,116 @@
};
&clock_cpucc {
+ compatible = "qcom,clk-cpu-osm-v2";
+
vdd-l3-supply = <&apc0_l3_vreg>;
vdd-pwrcl-supply = <&apc0_pwrcl_vreg>;
+ vdd-perfcl-supply = <&apc1_perfcl_vreg>;
+
+ qcom,l3-speedbin0-v0 =
+ < 300000000 0x000c000f 0x00002020 0x1 1 >,
+ < 403200000 0x500c0115 0x00002020 0x1 2 >,
+ < 480000000 0x50140219 0x00002020 0x1 3 >,
+ < 576000000 0x5014031e 0x00002020 0x1 4 >,
+ < 652800000 0x401c0422 0x00002020 0x1 5 >,
+ < 748800000 0x401c0527 0x00002020 0x1 6 >,
+ < 844800000 0x4024062c 0x00002323 0x2 7 >,
+ < 940800000 0x40240731 0x00002727 0x2 8 >,
+ < 1036800000 0x40240836 0x00002b2b 0x2 9 >,
+ < 1132800000 0x402c093b 0x00002f2f 0x2 10 >,
+ < 1209600000 0x402c0a3f 0x00003232 0x2 11 >,
+ < 1305600000 0x40340b44 0x00003636 0x2 12 >,
+ < 1401600000 0x40340c49 0x00003a3a 0x2 13 >,
+ < 1478400000 0x403c0d4d 0x00003e3e 0x2 14 >;
+
+ qcom,pwrcl-speedbin0-v0 =
+ < 300000000 0x000c000f 0x00002020 0x1 1 >,
+ < 403200000 0x500c0115 0x00002020 0x1 2 >,
+ < 480000000 0x50140219 0x00002020 0x1 3 >,
+ < 576000000 0x5014031e 0x00002020 0x1 4 >,
+ < 652800000 0x401c0422 0x00002020 0x1 5 >,
+ < 748800000 0x401c0527 0x00002020 0x1 6 >,
+ < 825600000 0x401c062b 0x00002222 0x1 7 >,
+ < 902400000 0x4024072f 0x00002626 0x1 8 >,
+ < 979200000 0x40240833 0x00002929 0x1 9 >,
+ < 1056000000 0x402c0937 0x00002c2c 0x2 10 >,
+ < 1132800000 0x402c0a3b 0x00002f2f 0x2 11 >,
+ < 1228800000 0x402c0b40 0x00003333 0x2 12 >,
+ < 1324800000 0x40340c45 0x00003737 0x2 13 >,
+ < 1420800000 0x40340d4a 0x00003b3b 0x2 14 >,
+ < 1516800000 0x403c0e4f 0x00003f3f 0x2 15 >,
+ < 1612800000 0x403c0f54 0x00004343 0x2 16 >,
+ < 1689600000 0x40441058 0x00004646 0x2 17 >,
+ < 1766400000 0x4044115c 0x00004a4a 0x2 18 >;
+
+ qcom,perfcl-speedbin0-v0 =
+ < 300000000 0x000c000f 0x00002020 0x1 1 >,
+ < 403200000 0x500c0115 0x00002020 0x1 2 >,
+ < 480000000 0x50140219 0x00002020 0x1 3 >,
+ < 576000000 0x5014031e 0x00002020 0x1 4 >,
+ < 652800000 0x401c0422 0x00002020 0x1 5 >,
+ < 748800000 0x401c0527 0x00002020 0x1 6 >,
+ < 825600000 0x401c062b 0x00002222 0x1 7 >,
+ < 902400000 0x4024072f 0x00002626 0x1 8 >,
+ < 979200000 0x40240833 0x00002929 0x1 9 >,
+ < 1056000000 0x402c0937 0x00002c2c 0x1 10 >,
+ < 1132800000 0x402c0a3b 0x00002f2f 0x1 11 >,
+ < 1209600000 0x402c0b3f 0x00003232 0x2 12 >,
+ < 1286400000 0x40340c43 0x00003636 0x2 13 >,
+ < 1363200000 0x40340d47 0x00003939 0x2 14 >,
+ < 1459200000 0x403c0e4c 0x00003d3d 0x2 15 >,
+ < 1536000000 0x403c0f50 0x00004040 0x2 16 >,
+ < 1612800000 0x403c1054 0x00004343 0x2 17 >,
+ < 1689600000 0x40441158 0x00004646 0x2 18 >,
+ < 1766400000 0x4044125c 0x00004a4a 0x2 19 >,
+ < 1843200000 0x40441360 0x00004d4d 0x2 20 >,
+ < 1920000000 0x404c1464 0x00005050 0x2 21 >,
+ < 1996800000 0x404c1568 0x00005353 0x2 22 >,
+ < 2092800000 0x4054166d 0x00005757 0x2 23 >,
+ < 2169600000 0x40541771 0x00005a5a 0x2 24 >,
+ < 2246400000 0x40541875 0x00005e5e 0x2 25 >,
+ < 2323200000 0x40541979 0x00006161 0x2 26 >,
+ < 2400000000 0x40541a7d 0x00006464 0x2 27 >;
+
+ qcom,perfcl-speedbin1-v0 =
+ < 300000000 0x000c000f 0x00002020 0x1 1 >,
+ < 403200000 0x500c0115 0x00002020 0x1 2 >,
+ < 480000000 0x50140219 0x00002020 0x1 3 >,
+ < 576000000 0x5014031e 0x00002020 0x1 4 >,
+ < 652800000 0x401c0422 0x00002020 0x1 5 >,
+ < 748800000 0x401c0527 0x00002020 0x1 6 >,
+ < 825600000 0x401c062b 0x00002222 0x1 7 >,
+ < 902400000 0x4024072f 0x00002626 0x1 8 >,
+ < 979200000 0x40240833 0x00002929 0x1 9 >,
+ < 1056000000 0x402c0937 0x00002c2c 0x1 10 >,
+ < 1132800000 0x402c0a3b 0x00002f2f 0x1 11 >,
+ < 1209600000 0x402c0b3f 0x00003232 0x2 12 >,
+ < 1286400000 0x40340c43 0x00003636 0x2 13 >,
+ < 1363200000 0x40340d47 0x00003939 0x2 14 >,
+ < 1459200000 0x403c0e4c 0x00003d3d 0x2 15 >,
+ < 1536000000 0x403c0f50 0x00004040 0x2 16 >,
+ < 1612800000 0x403c1054 0x00004343 0x2 17 >,
+ < 1689600000 0x40441158 0x00004646 0x2 18 >,
+ < 1766400000 0x4044125c 0x00004a4a 0x2 19 >,
+ < 1843200000 0x40441360 0x00004d4d 0x2 20 >,
+ < 1920000000 0x404c1464 0x00005050 0x2 21 >,
+ < 1996800000 0x404c1568 0x00005353 0x2 22 >,
+ < 2092800000 0x4054166d 0x00005757 0x2 23 >,
+ < 2169600000 0x40541771 0x00005a5a 0x2 24 >,
+ < 2246400000 0x40541875 0x00005e5e 0x2 25 >,
+ < 2323200000 0x40541979 0x00006161 0x2 26 >,
+ < 2400000000 0x40541a7d 0x00006464 0x2 27 >,
+ < 2476800000 0x40541b81 0x00006767 0x2 28 >,
+ < 2553600000 0x40541c85 0x00006a6a 0x2 29 >,
+ < 2630400000 0x40541d89 0x00006e6e 0x2 30 >,
+ < 2707200000 0x40541e8d 0x00007171 0x2 31 >;
+
+ qcom,l3-memacc-level-vc-bin0 = <8 13>;
+
+ qcom,pwrcl-memacc-level-vc-bin0 = <12 16>;
+
+ qcom,perfcl-memacc-level-vc-bin0 = <14 22>;
+ qcom,perfcl-memacc-level-vc-bin1 = <14 22>;
};
&clock_gcc {
@@ -450,10 +558,22 @@
compatible = "qcom,dispcc-sdm845-v2";
};
+&clock_gpucc {
+ compatible = "qcom,gpucc-sdm845-v2";
+};
+
+&clock_gfx {
+ compatible = "qcom,gfxcc-sdm845-v2";
+};
+
&clock_videocc {
compatible = "qcom,video_cc-sdm845-v2";
};
+&clock_aop {
+ compatible = "qcom,aop-qmp-clk-v2";
+};
+
&msm_vidc {
qcom,allowed-clock-rates = <100000000 200000000 330000000
404000000 444000000 533000000>;
@@ -464,3 +584,7 @@
qcom,spss-test-firmware-name = "spss2t"; /* 8 chars max */
qcom,spss-prod-firmware-name = "spss2p"; /* 8 chars max */
};
+
+&mdss_mdp {
+ clock-max-rate = <0 0 0 0 430000000 19200000 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi b/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi
index 1c07c5e..42299cd 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi
@@ -79,7 +79,7 @@
label = "venus-llcc";
qcom,bus-master = <MSM_BUS_MASTER_VIDEO_P0>;
qcom,bus-slave = <MSM_BUS_SLAVE_LLCC>;
- qcom,bus-governor = "performance";
+ qcom,bus-governor = "msm-vidc-llcc";
qcom,bus-range-kbps = <17000 125700>;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index f408719..41164cd 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -29,7 +29,7 @@
/ {
model = "Qualcomm Technologies, Inc. SDM845";
compatible = "qcom,sdm845";
- qcom,msm-id = <321 0x0>;
+ qcom,msm-id = <321 0x10000>;
interrupt-parent = <&pdc>;
aliases {
@@ -1152,8 +1152,8 @@
< 652800000 0x401c0422 0x00002020 0x1 5 >,
< 729600000 0x401c0526 0x00002020 0x1 6 >,
< 806400000 0x401c062a 0x00002222 0x1 7 >,
- < 883200000 0x4024072e 0x00002525 0x2 8 >,
- < 960000000 0x40240832 0x00002828 0x2 9 >;
+ < 883200000 0x4024072e 0x00002525 0x1 8 >,
+ < 960000000 0x40240832 0x00002828 0x1 9 >;
qcom,l3-speedbin1-v0 =
< 300000000 0x000c000f 0x00002020 0x1 1 >,
@@ -1163,10 +1163,10 @@
< 652800000 0x401c0422 0x00002020 0x1 5 >,
< 729600000 0x401c0526 0x00002020 0x1 6 >,
< 806400000 0x401c062a 0x00002222 0x1 7 >,
- < 883200000 0x4024072e 0x00002525 0x2 8 >,
- < 960000000 0x40240832 0x00002828 0x2 9 >,
- < 1036800000 0x40240936 0x00002b2b 0x3 10 >,
- < 1094400000 0x402c0a39 0x00002e2e 0x3 11 >;
+ < 883200000 0x4024072e 0x00002525 0x1 8 >,
+ < 960000000 0x40240832 0x00002828 0x1 9 >,
+ < 1036800000 0x40240936 0x00002b2b 0x1 10 >,
+ < 1094400000 0x402c0a39 0x00002e2e 0x1 11 >;
qcom,l3-speedbin2-v0 =
< 300000000 0x000c000f 0x00002020 0x1 1 >,
@@ -1176,12 +1176,12 @@
< 652800000 0x401c0422 0x00002020 0x1 5 >,
< 729600000 0x401c0526 0x00002020 0x1 6 >,
< 806400000 0x401c062a 0x00002222 0x1 7 >,
- < 883200000 0x4024072e 0x00002525 0x2 8 >,
- < 960000000 0x40240832 0x00002828 0x2 9 >,
- < 1036800000 0x40240936 0x00002b2b 0x3 10 >,
- < 1113600000 0x402c0a3a 0x00002e2e 0x3 11 >,
- < 1209600000 0x402c0b3f 0x00003232 0x3 12 >,
- < 1305600000 0x40340c44 0x00003636 0x3 13 >;
+ < 883200000 0x4024072e 0x00002525 0x1 8 >,
+ < 960000000 0x40240832 0x00002828 0x1 9 >,
+ < 1036800000 0x40240936 0x00002b2b 0x1 10 >,
+ < 1113600000 0x402c0a3a 0x00002e2e 0x1 11 >,
+ < 1209600000 0x402c0b3f 0x00003232 0x1 12 >,
+ < 1305600000 0x40340c44 0x00003636 0x1 13 >;
qcom,pwrcl-speedbin0-v0 =
< 300000000 0x000c000f 0x00002020 0x1 1 >,
@@ -1196,11 +1196,11 @@
< 1056000000 0x402c0937 0x00002c2c 0x1 10 >,
< 1132800000 0x402c0a3b 0x00002f2f 0x1 11 >,
< 1209600000 0x402c0b3f 0x00003232 0x1 12 >,
- < 1286400000 0x40340c43 0x00003636 0x2 13 >,
- < 1363200000 0x40340d47 0x00003939 0x2 14 >,
- < 1440000000 0x40340e4b 0x00003c3c 0x2 15 >,
- < 1516800000 0x403c0f4f 0x00003f3f 0x2 16 >,
- < 1593600000 0x403c1053 0x00004242 0x2 17 >;
+ < 1286400000 0x40340c43 0x00003636 0x1 13 >,
+ < 1363200000 0x40340d47 0x00003939 0x1 14 >,
+ < 1440000000 0x40340e4b 0x00003c3c 0x1 15 >,
+ < 1516800000 0x403c0f4f 0x00003f3f 0x1 16 >,
+ < 1593600000 0x403c1053 0x00004242 0x1 17 >;
qcom,pwrcl-speedbin1-v0 =
< 300000000 0x000c000f 0x00002020 0x1 1 >,
@@ -1215,13 +1215,13 @@
< 1056000000 0x402c0937 0x00002c2c 0x1 10 >,
< 1132800000 0x402c0a3b 0x00002f2f 0x1 11 >,
< 1209600000 0x402c0b3f 0x00003232 0x1 12 >,
- < 1286400000 0x40340c43 0x00003636 0x2 13 >,
- < 1363200000 0x40340d47 0x00003939 0x2 14 >,
- < 1440000000 0x40340e4b 0x00003c3c 0x2 15 >,
- < 1516800000 0x403c0f4f 0x00003f3f 0x2 16 >,
- < 1593600000 0x403c1053 0x00004242 0x2 17 >,
- < 1651200000 0x403c1156 0x00004545 0x3 18 >,
- < 1708800000 0x40441259 0x00004747 0x3 19 >;
+ < 1286400000 0x40340c43 0x00003636 0x1 13 >,
+ < 1363200000 0x40340d47 0x00003939 0x1 14 >,
+ < 1440000000 0x40340e4b 0x00003c3c 0x1 15 >,
+ < 1516800000 0x403c0f4f 0x00003f3f 0x1 16 >,
+ < 1593600000 0x403c1053 0x00004242 0x1 17 >,
+ < 1651200000 0x403c1156 0x00004545 0x1 18 >,
+ < 1708800000 0x40441259 0x00004747 0x1 19 >;
qcom,pwrcl-speedbin2-v0 =
< 300000000 0x000c000f 0x00002020 0x1 1 >,
@@ -1236,13 +1236,13 @@
< 1056000000 0x402c0937 0x00002c2c 0x1 10 >,
< 1132800000 0x402c0a3b 0x00002f2f 0x1 11 >,
< 1209600000 0x402c0b3f 0x00003232 0x1 12 >,
- < 1286400000 0x40340c43 0x00003636 0x2 13 >,
- < 1363200000 0x40340d47 0x00003939 0x2 14 >,
- < 1440000000 0x40340e4b 0x00003c3c 0x2 15 >,
- < 1516800000 0x403c0f4f 0x00003f3f 0x2 16 >,
- < 1593600000 0x403c1053 0x00004242 0x2 17 >,
- < 1670400000 0x40441157 0x00004646 0x3 18 >,
- < 1747200000 0x4044125b 0x00004949 0x3 19 >;
+ < 1286400000 0x40340c43 0x00003636 0x1 13 >,
+ < 1363200000 0x40340d47 0x00003939 0x1 14 >,
+ < 1440000000 0x40340e4b 0x00003c3c 0x1 15 >,
+ < 1516800000 0x403c0f4f 0x00003f3f 0x1 16 >,
+ < 1593600000 0x403c1053 0x00004242 0x1 17 >,
+ < 1670400000 0x40441157 0x00004646 0x1 18 >,
+ < 1747200000 0x4044125b 0x00004949 0x1 19 >;
qcom,perfcl-speedbin0-v0 =
< 300000000 0x000c000f 0x00002020 0x1 1 >,
@@ -1257,16 +1257,16 @@
< 1036800000 0x40240936 0x00002b2b 0x1 10 >,
< 1113600000 0x402c0a3a 0x00002e2e 0x1 11 >,
< 1190400000 0x402c0b3e 0x00003232 0x1 12 >,
- < 1267200000 0x40340c42 0x00003535 0x2 13 >,
- < 1344000000 0x40340d46 0x00003838 0x2 14 >,
- < 1420800000 0x40340e4a 0x00003b3b 0x2 15 >,
- < 1497600000 0x403c0f4e 0x00003e3e 0x2 16 >,
- < 1574400000 0x403c1052 0x00004242 0x2 17 >,
- < 1651200000 0x403c1156 0x00004545 0x2 18 >,
- < 1728000000 0x4044125a 0x00004848 0x3 19 >,
- < 1804800000 0x4044135e 0x00004b4b 0x3 20 >,
- < 1881600000 0x404c1462 0x00004e4e 0x3 21 >,
- < 1958400000 0x404c1566 0x00005252 0x3 22 >;
+ < 1267200000 0x40340c42 0x00003535 0x1 13 >,
+ < 1344000000 0x40340d46 0x00003838 0x1 14 >,
+ < 1420800000 0x40340e4a 0x00003b3b 0x1 15 >,
+ < 1497600000 0x403c0f4e 0x00003e3e 0x1 16 >,
+ < 1574400000 0x403c1052 0x00004242 0x1 17 >,
+ < 1651200000 0x403c1156 0x00004545 0x1 18 >,
+ < 1728000000 0x4044125a 0x00004848 0x1 19 >,
+ < 1804800000 0x4044135e 0x00004b4b 0x1 20 >,
+ < 1881600000 0x404c1462 0x00004e4e 0x1 21 >,
+ < 1958400000 0x404c1566 0x00005252 0x1 22 >;
qcom,perfcl-speedbin1-v0 =
< 300000000 0x000c000f 0x00002020 0x1 1 >,
@@ -1281,18 +1281,18 @@
< 1036800000 0x40240936 0x00002b2b 0x1 10 >,
< 1113600000 0x402c0a3a 0x00002e2e 0x1 11 >,
< 1190400000 0x402c0b3e 0x00003232 0x1 12 >,
- < 1267200000 0x40340c42 0x00003535 0x2 13 >,
- < 1344000000 0x40340d46 0x00003838 0x2 14 >,
- < 1420800000 0x40340e4a 0x00003b3b 0x2 15 >,
- < 1497600000 0x403c0f4e 0x00003e3e 0x2 16 >,
- < 1574400000 0x403c1052 0x00004242 0x2 17 >,
- < 1651200000 0x403c1156 0x00004545 0x2 18 >,
- < 1728000000 0x4044125a 0x00004848 0x3 19 >,
- < 1804800000 0x4044135e 0x00004b4b 0x3 20 >,
- < 1881600000 0x404c1462 0x00004e4e 0x3 21 >,
- < 1958400000 0x404c1566 0x00005252 0x3 22 >,
- < 2035200000 0x404c166a 0x00005555 0x3 23 >,
- < 2092800000 0x4054176d 0x00005757 0x3 24 >;
+ < 1267200000 0x40340c42 0x00003535 0x1 13 >,
+ < 1344000000 0x40340d46 0x00003838 0x1 14 >,
+ < 1420800000 0x40340e4a 0x00003b3b 0x1 15 >,
+ < 1497600000 0x403c0f4e 0x00003e3e 0x1 16 >,
+ < 1574400000 0x403c1052 0x00004242 0x1 17 >,
+ < 1651200000 0x403c1156 0x00004545 0x1 18 >,
+ < 1728000000 0x4044125a 0x00004848 0x1 19 >,
+ < 1804800000 0x4044135e 0x00004b4b 0x1 20 >,
+ < 1881600000 0x404c1462 0x00004e4e 0x1 21 >,
+ < 1958400000 0x404c1566 0x00005252 0x1 22 >,
+ < 2035200000 0x404c166a 0x00005555 0x1 23 >,
+ < 2092800000 0x4054176d 0x00005757 0x1 24 >;
qcom,perfcl-speedbin2-v0 =
< 300000000 0x000c000f 0x00002020 0x1 1 >,
@@ -1307,19 +1307,31 @@
< 1036800000 0x40240936 0x00002b2b 0x1 10 >,
< 1113600000 0x402c0a3a 0x00002e2e 0x1 11 >,
< 1190400000 0x402c0b3e 0x00003232 0x1 12 >,
- < 1267200000 0x40340c42 0x00003535 0x2 13 >,
- < 1344000000 0x40340d46 0x00003838 0x2 14 >,
- < 1420800000 0x40340e4a 0x00003b3b 0x2 15 >,
- < 1497600000 0x403c0f4e 0x00003e3e 0x2 16 >,
- < 1574400000 0x403c1052 0x00004242 0x2 17 >,
- < 1651200000 0x403c1156 0x00004545 0x2 18 >,
- < 1728000000 0x4044125a 0x00004848 0x3 19 >,
- < 1804800000 0x4044135e 0x00004b4b 0x3 20 >,
- < 1881600000 0x404c1462 0x00004e4e 0x3 21 >,
- < 1958400000 0x404c1566 0x00005252 0x3 22 >,
- < 2035200000 0x404c166a 0x00005555 0x3 23 >,
- < 2112000000 0x4054176e 0x00005858 0x3 24 >,
- < 2208000000 0x40541873 0x00005c5c 0x3 25 >;
+ < 1267200000 0x40340c42 0x00003535 0x1 13 >,
+ < 1344000000 0x40340d46 0x00003838 0x1 14 >,
+ < 1420800000 0x40340e4a 0x00003b3b 0x1 15 >,
+ < 1497600000 0x403c0f4e 0x00003e3e 0x1 16 >,
+ < 1574400000 0x403c1052 0x00004242 0x1 17 >,
+ < 1651200000 0x403c1156 0x00004545 0x1 18 >,
+ < 1728000000 0x4044125a 0x00004848 0x1 19 >,
+ < 1804800000 0x4044135e 0x00004b4b 0x1 20 >,
+ < 1881600000 0x404c1462 0x00004e4e 0x1 21 >,
+ < 1958400000 0x404c1566 0x00005252 0x1 22 >,
+ < 2035200000 0x404c166a 0x00005555 0x1 23 >,
+ < 2112000000 0x4054176e 0x00005858 0x1 24 >,
+ < 2208000000 0x40541873 0x00005c5c 0x1 25 >;
+
+ qcom,l3-memacc-level-vc-bin0 = <7 63>;
+ qcom,l3-memacc-level-vc-bin1 = <7 9>;
+ qcom,l3-memacc-level-vc-bin2 = <7 9>;
+
+ qcom,pwrcl-memacc-level-vc-bin0 = <12 63>;
+ qcom,pwrcl-memacc-level-vc-bin1 = <12 17>;
+ qcom,pwrcl-memacc-level-vc-bin2 = <12 17>;
+
+ qcom,perfcl-memacc-level-vc-bin0 = <12 18>;
+ qcom,perfcl-memacc-level-vc-bin1 = <12 18>;
+ qcom,perfcl-memacc-level-vc-bin2 = <12 18>;
qcom,up-timer =
<1000 1000 1000>;
@@ -1390,7 +1402,7 @@
};
clock_aop: qcom,aopclk {
- compatible = "qcom,aop-qmp-clk";
+ compatible = "qcom,aop-qmp-clk-v1";
#clock-cells = <1>;
mboxes = <&qmp_aop 0>;
mbox-names = "qdss_clk";
@@ -2531,6 +2543,18 @@
qcom,fragmented-data;
};
+ qcom,qsee_ipc_irq_bridge {
+ compatible = "qcom,qsee-ipc-irq-bridge";
+
+ qcom,qsee-ipq-irq-spss {
+ qcom,rx-irq-clr = <0x1888008 0x4>;
+ qcom,rx-irq-clr-mask = <0x2>;
+ qcom,dev-name = "qsee_ipc_irq_spss";
+ interrupts = <0 349 4>;
+ label = "spss";
+ };
+ };
+
qcom,spcom {
compatible = "qcom,spcom";
@@ -2708,6 +2732,10 @@
<&apps_smmu 0x712 0x1>;
};
+ qcom_msmhdcp: qcom,msm_hdcp {
+ compatible = "qcom,msm-hdcp";
+ };
+
qcom_crypto: qcrypto@1de0000 {
compatible = "qcom,qcrypto";
reg = <0x1de0000 0x20000>,
diff --git a/arch/arm64/configs/sdm670_defconfig b/arch/arm64/configs/sdm670_defconfig
index f5c62aa..6d41d516 100644
--- a/arch/arm64/configs/sdm670_defconfig
+++ b/arch/arm64/configs/sdm670_defconfig
@@ -508,7 +508,6 @@
CONFIG_MSM_EVENT_TIMER=y
CONFIG_MSM_PM=y
CONFIG_MSM_QBT1000=y
-CONFIG_APSS_CORE_EA=y
CONFIG_QCOM_DCC_V2=y
CONFIG_QTI_RPM_STATS_LOG=y
CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig
index f1dcb9d..e835d46 100644
--- a/arch/arm64/configs/sdm845-perf_defconfig
+++ b/arch/arm64/configs/sdm845-perf_defconfig
@@ -531,6 +531,7 @@
CONFIG_QTI_RPM_STATS_LOG=y
CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
CONFIG_QMP_DEBUGFS_CLIENT=y
+CONFIG_QSEE_IPC_IRQ_BRIDGE=y
CONFIG_QCOM_BIMC_BWMON=y
CONFIG_ARM_MEMLAT_MON=y
CONFIG_QCOMCCI_HWMON=y
@@ -588,6 +589,7 @@
CONFIG_HARDENED_USERCOPY=y
CONFIG_SECURITY_SELINUX=y
CONFIG_SECURITY_SMACK=y
+CONFIG_CRYPTO_CTR=y
CONFIG_CRYPTO_XCBC=y
CONFIG_CRYPTO_MD4=y
CONFIG_CRYPTO_TWOFISH=y
diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig
index 3aefe13..c26a3c4 100644
--- a/arch/arm64/configs/sdm845_defconfig
+++ b/arch/arm64/configs/sdm845_defconfig
@@ -550,6 +550,7 @@
CONFIG_QTI_RPM_STATS_LOG=y
CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
CONFIG_QMP_DEBUGFS_CLIENT=y
+CONFIG_QSEE_IPC_IRQ_BRIDGE=y
CONFIG_QCOM_BIMC_BWMON=y
CONFIG_ARM_MEMLAT_MON=y
CONFIG_QCOMCCI_HWMON=y
@@ -656,6 +657,7 @@
CONFIG_HARDENED_USERCOPY=y
CONFIG_SECURITY_SELINUX=y
CONFIG_SECURITY_SMACK=y
+CONFIG_CRYPTO_CTR=y
CONFIG_CRYPTO_XCBC=y
CONFIG_CRYPTO_MD4=y
CONFIG_CRYPTO_TWOFISH=y
diff --git a/arch/arm64/include/asm/stackprotector.h b/arch/arm64/include/asm/stackprotector.h
index fe5e287..b86a086 100644
--- a/arch/arm64/include/asm/stackprotector.h
+++ b/arch/arm64/include/asm/stackprotector.h
@@ -30,6 +30,7 @@
/* Try to get a semi random initial value. */
get_random_bytes(&canary, sizeof(canary));
canary ^= LINUX_VERSION_CODE;
+ canary &= CANARY_MASK;
current->stack_canary = canary;
__stack_chk_guard = current->stack_canary;
diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h
index 2df5d5f..4d9222a 100644
--- a/arch/arm64/include/asm/uaccess.h
+++ b/arch/arm64/include/asm/uaccess.h
@@ -383,9 +383,9 @@
{
unsigned long res = n;
kasan_check_write(to, n);
+ check_object_size(to, n, false);
if (access_ok(VERIFY_READ, from, n)) {
- check_object_size(to, n, false);
res = __arch_copy_from_user(to, from, n);
}
if (unlikely(res))
@@ -396,9 +396,9 @@
static inline unsigned long __must_check copy_to_user(void __user *to, const void *from, unsigned long n)
{
kasan_check_read(from, n);
+ check_object_size(from, n, true);
if (access_ok(VERIFY_WRITE, to, n)) {
- check_object_size(from, n, true);
n = __arch_copy_to_user(to, from, n);
}
return n;
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index acbe515..7f90b7e 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -157,12 +157,13 @@
dma_addr_t *dma_handle, gfp_t flags,
unsigned long attrs)
{
+ void *addr;
+
if (IS_ENABLED(CONFIG_ZONE_DMA) &&
dev->coherent_dma_mask <= DMA_BIT_MASK(32))
flags |= GFP_DMA;
if (dev_get_cma_area(dev) && gfpflags_allow_blocking(flags)) {
struct page *page;
- void *addr;
page = dma_alloc_from_contiguous(dev, size >> PAGE_SHIFT,
get_order(size));
@@ -172,20 +173,20 @@
*dma_handle = phys_to_dma(dev, page_to_phys(page));
addr = page_address(page);
memset(addr, 0, size);
-
- if ((attrs & DMA_ATTR_NO_KERNEL_MAPPING) ||
- (attrs & DMA_ATTR_STRONGLY_ORDERED)) {
- /*
- * flush the caches here because we can't later
- */
- __dma_flush_area(addr, size);
- __dma_remap(page, size, __pgprot(0), true);
- }
-
- return addr;
} else {
- return swiotlb_alloc_coherent(dev, size, dma_handle, flags);
+ addr = swiotlb_alloc_coherent(dev, size, dma_handle, flags);
}
+
+ if (addr && ((attrs & DMA_ATTR_NO_KERNEL_MAPPING) ||
+ (attrs & DMA_ATTR_STRONGLY_ORDERED))) {
+ /*
+ * flush the caches here because we can't later
+ */
+ __dma_flush_area(addr, size);
+ __dma_remap(virt_to_page(addr), size, __pgprot(0), true);
+ }
+
+ return addr;
}
static void __dma_free_coherent(struct device *dev, size_t size,
diff --git a/drivers/bluetooth/btfm_slim.c b/drivers/bluetooth/btfm_slim.c
index f50bf6f..8f0e632 100644
--- a/drivers/bluetooth/btfm_slim.c
+++ b/drivers/bluetooth/btfm_slim.c
@@ -496,9 +496,18 @@
/* Driver specific data allocation */
btfm_slim->dev = &slim->dev;
ret = btfm_slim_register_codec(&slim->dev);
+ if (ret) {
+ BTFMSLIM_ERR("error, registering slimbus codec failed");
+ goto free;
+ }
ret = bt_register_slimdev(&slim->dev);
+ if (ret < 0) {
+ btfm_slim_unregister_codec(&slim->dev);
+ goto free;
+ }
return ret;
-
+free:
+ slim_remove_device(&btfm_slim->slim_ifd);
dealloc:
mutex_destroy(&btfm_slim->io_lock);
mutex_destroy(&btfm_slim->xfer_lock);
diff --git a/drivers/bluetooth/btfm_slim.h b/drivers/bluetooth/btfm_slim.h
index ed3a743..cc9d14d 100644
--- a/drivers/bluetooth/btfm_slim.h
+++ b/drivers/bluetooth/btfm_slim.h
@@ -162,4 +162,12 @@
* 0
*/
int btfm_slim_register_codec(struct device *dev);
+
+/**
+ * btfm_slim_unregister_codec: Unregister codec driver in slimbus device node
+ * @dev: device node
+ * Returns:
+ * VOID
+ */
+void btfm_slim_unregister_codec(struct device *dev);
#endif /* BTFM_SLIM_H */
diff --git a/drivers/bluetooth/btfm_slim_codec.c b/drivers/bluetooth/btfm_slim_codec.c
index 791ea29..b5c42fcc 100644
--- a/drivers/bluetooth/btfm_slim_codec.c
+++ b/drivers/bluetooth/btfm_slim_codec.c
@@ -462,5 +462,12 @@
return ret;
}
+void btfm_slim_unregister_codec(struct device *dev)
+{
+ BTFMSLIM_DBG("");
+ /* Unregister Codec driver */
+ snd_soc_unregister_codec(dev);
+}
+
MODULE_DESCRIPTION("BTFM Slimbus Codec driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 031ba29..d1e01bd 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -284,6 +284,7 @@
int cid;
int ssrcount;
int pd;
+ int file_close;
struct fastrpc_apps *apps;
struct fastrpc_perf perf;
struct dentry *debugfs_file;
@@ -480,7 +481,7 @@
if (!IS_ERR_OR_NULL(map->handle))
ion_free(fl->apps->client, map->handle);
- if (sess->smmu.enabled) {
+ if (sess && sess->smmu.enabled) {
if (map->size || map->phys)
msm_dma_unmap_sg(sess->dev,
map->table->sgl,
@@ -558,7 +559,9 @@
sess = fl->secsctx;
else
sess = fl->sctx;
-
+ VERIFY(err, !IS_ERR_OR_NULL(sess));
+ if (err)
+ goto bail;
VERIFY(err, !IS_ERR_OR_NULL(map->buf = dma_buf_get(fd)));
if (err)
goto bail;
@@ -1896,6 +1899,9 @@
return 0;
}
(void)fastrpc_release_current_dsp_process(fl);
+ spin_lock(&fl->hlock);
+ fl->file_close = 1;
+ spin_unlock(&fl->hlock);
fastrpc_context_list_dtor(fl);
fastrpc_buf_list_free(fl);
hlist_for_each_entry_safe(map, n, &fl->maps, hn) {
@@ -2272,6 +2278,14 @@
p.inv.fds = 0;
p.inv.attrs = 0;
p.inv.crc = NULL;
+ spin_lock(&fl->hlock);
+ if (fl->file_close == 1) {
+ err = EBADF;
+ pr_warn("ADSPRPC: fastrpc_device_release is happening, So not sending any new requests to DSP");
+ spin_unlock(&fl->hlock);
+ goto bail;
+ }
+ spin_unlock(&fl->hlock);
switch (ioctl_num) {
case FASTRPC_IOCTL_INVOKE:
@@ -2473,7 +2487,7 @@
start = 0x60000000;
VERIFY(err, !IS_ERR_OR_NULL(sess->smmu.mapping =
arm_iommu_create_mapping(&platform_bus_type,
- start, 0x7fffffff)));
+ start, 0x78000000)));
if (err)
goto bail;
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 08d1dd5..ee737ef 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -2044,8 +2044,8 @@
struct batched_entropy {
union {
- unsigned long entropy_long[CHACHA20_BLOCK_SIZE / sizeof(unsigned long)];
- unsigned int entropy_int[CHACHA20_BLOCK_SIZE / sizeof(unsigned int)];
+ u64 entropy_u64[CHACHA20_BLOCK_SIZE / sizeof(u64)];
+ u32 entropy_u32[CHACHA20_BLOCK_SIZE / sizeof(u32)];
};
unsigned int position;
};
@@ -2055,52 +2055,51 @@
* number is either as good as RDRAND or as good as /dev/urandom, with the
* goal of being quite fast and not depleting entropy.
*/
-static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_long);
-unsigned long get_random_long(void)
+static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_u64);
+u64 get_random_u64(void)
{
- unsigned long ret;
+ u64 ret;
struct batched_entropy *batch;
- if (arch_get_random_long(&ret))
+#if BITS_PER_LONG == 64
+ if (arch_get_random_long((unsigned long *)&ret))
return ret;
+#else
+ if (arch_get_random_long((unsigned long *)&ret) &&
+ arch_get_random_long((unsigned long *)&ret + 1))
+ return ret;
+#endif
- batch = &get_cpu_var(batched_entropy_long);
- if (batch->position % ARRAY_SIZE(batch->entropy_long) == 0) {
- extract_crng((u8 *)batch->entropy_long);
+ batch = &get_cpu_var(batched_entropy_u64);
+ if (batch->position % ARRAY_SIZE(batch->entropy_u64) == 0) {
+ extract_crng((u8 *)batch->entropy_u64);
batch->position = 0;
}
- ret = batch->entropy_long[batch->position++];
- put_cpu_var(batched_entropy_long);
+ ret = batch->entropy_u64[batch->position++];
+ put_cpu_var(batched_entropy_u64);
return ret;
}
-EXPORT_SYMBOL(get_random_long);
+EXPORT_SYMBOL(get_random_u64);
-#if BITS_PER_LONG == 32
-unsigned int get_random_int(void)
+static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_u32);
+u32 get_random_u32(void)
{
- return get_random_long();
-}
-#else
-static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_int);
-unsigned int get_random_int(void)
-{
- unsigned int ret;
+ u32 ret;
struct batched_entropy *batch;
if (arch_get_random_int(&ret))
return ret;
- batch = &get_cpu_var(batched_entropy_int);
- if (batch->position % ARRAY_SIZE(batch->entropy_int) == 0) {
- extract_crng((u8 *)batch->entropy_int);
+ batch = &get_cpu_var(batched_entropy_u32);
+ if (batch->position % ARRAY_SIZE(batch->entropy_u32) == 0) {
+ extract_crng((u8 *)batch->entropy_u32);
batch->position = 0;
}
- ret = batch->entropy_int[batch->position++];
- put_cpu_var(batched_entropy_int);
+ ret = batch->entropy_u32[batch->position++];
+ put_cpu_var(batched_entropy_u32);
return ret;
}
-#endif
-EXPORT_SYMBOL(get_random_int);
+EXPORT_SYMBOL(get_random_u32);
/**
* randomize_page - Generate a random, page aligned address
diff --git a/drivers/clk/qcom/clk-aop-qmp.c b/drivers/clk/qcom/clk-aop-qmp.c
index f6aeb19..ff229fb 100644
--- a/drivers/clk/qcom/clk-aop-qmp.c
+++ b/drivers/clk/qcom/clk-aop-qmp.c
@@ -30,7 +30,7 @@
void *data;
};
-#define DEFINE_CLK_AOP_QMP(_name, _class, _res, _estate, _dstate) \
+#define DEFINE_CLK_AOP_QMP(_name, _class, _res, _estate, _dstate, _flags) \
static struct clk_aop_qmp _name = { \
.msg.class = #_class, \
.msg.res = #_res, \
@@ -40,7 +40,7 @@
.ops = &aop_qmp_clk_ops, \
.name = #_name, \
.num_parents = 0, \
- .flags = CLK_ENABLE_HAND_OFF, \
+ .flags = _flags, \
}, \
}
@@ -214,13 +214,25 @@
.is_enabled = clk_aop_qmp_is_enabled,
};
-DEFINE_CLK_AOP_QMP(qdss_qmp_clk, clock, qdss,
- QDSS_CLK_LEVEL_DYNAMIC, QDSS_CLK_LEVEL_OFF);
+DEFINE_CLK_AOP_QMP(qdss_qmp_clk, clock, qdss, QDSS_CLK_LEVEL_DYNAMIC,
+ QDSS_CLK_LEVEL_OFF, CLK_ENABLE_HAND_OFF);
+DEFINE_CLK_AOP_QMP(qdss_ao_qmp_clk, clock, qdss_ao, QDSS_CLK_LEVEL_DYNAMIC,
+ QDSS_CLK_LEVEL_OFF, 0);
static struct clk_hw *aop_qmp_clk_hws[] = {
[QDSS_CLK] = &qdss_qmp_clk.hw,
+ [QDSS_AO_CLK] = &qdss_ao_qmp_clk.hw,
};
+/*
+ * Due to HW limitations on v1, the qdss_ao clock was not supported by the clock
+ * driver on AOP.
+ */
+static void aop_qmp_fixup_v1(void)
+{
+ aop_qmp_clk_hws[QDSS_AO_CLK] = NULL;
+}
+
static int qmp_update_client(struct clk_hw *hw, struct device *dev,
struct mbox_chan *mbox)
{
@@ -250,7 +262,7 @@
static int aop_qmp_clk_probe(struct platform_device *pdev)
{
- struct clk *clk;
+ struct clk *clk = NULL;
struct device_node *np = pdev->dev.of_node;
struct mbox_chan *mbox = NULL;
int num_clks = ARRAY_SIZE(aop_qmp_clk_hws);
@@ -264,7 +276,12 @@
if (ret < 0)
return ret;
+ if (of_device_is_compatible(pdev->dev.of_node, "qcom,aop-qmp-clk-v1"))
+ aop_qmp_fixup_v1();
+
for (i = 1; i < num_clks; i++) {
+ if (!aop_qmp_clk_hws[i])
+ continue;
ret = qmp_update_client(aop_qmp_clk_hws[i], &pdev->dev, mbox);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to update QMP client %d\n",
@@ -273,13 +290,17 @@
}
}
- for (i = 0; i < num_clks; i++) {
- ret = clk_aop_qmp_prepare(aop_qmp_clk_hws[i]);
- if (ret < 0)
- goto fail;
- }
+ /*
+ * Proxy vote on the QDSS clock. This is needed to avoid issues with
+ * excessive requests on the QMP layer during the QDSS driver probe.
+ */
+ ret = clk_aop_qmp_prepare(&qdss_qmp_clk.hw);
+ if (ret < 0)
+ goto fail;
for (i = 0; i < num_clks; i++) {
+ if (!aop_qmp_clk_hws[i])
+ continue;
clk = devm_clk_register(&pdev->dev, aop_qmp_clk_hws[i]);
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
@@ -303,7 +324,8 @@
}
static const struct of_device_id aop_qmp_clk_of_match[] = {
- { .compatible = "qcom,aop-qmp-clk", },
+ { .compatible = "qcom,aop-qmp-clk-v1" },
+ { .compatible = "qcom,aop-qmp-clk-v2" },
{}
};
diff --git a/drivers/clk/qcom/clk-cpu-osm.c b/drivers/clk/qcom/clk-cpu-osm.c
index 1e49722..4158e65 100644
--- a/drivers/clk/qcom/clk-cpu-osm.c
+++ b/drivers/clk/qcom/clk-cpu-osm.c
@@ -122,6 +122,7 @@
#define MIN_VCO_VAL 0x2b
#define MAX_VC 63
+#define MEM_ACC_LEVELS_LUT 2
#define MAX_MEM_ACC_LEVELS 3
#define MAX_MEM_ACC_VAL_PER_LEVEL 3
#define MAX_MEM_ACC_VALUES (MAX_MEM_ACC_LEVELS * \
@@ -266,6 +267,7 @@
u32 speedbin;
u32 mem_acc_crossover_vc_addr;
u32 mem_acc_addr[MEM_ACC_ADDRS];
+ u32 mem_acc_level_vc[MEM_ACC_LEVELS_LUT];
u32 ramp_ctl_addr;
u32 apm_mode_ctl;
u32 apm_status_ctl;
@@ -1045,21 +1047,6 @@
static void clk_osm_program_mem_acc_regs(struct clk_osm *c)
{
- int curr_level, i, j = 0;
- int mem_acc_level_map[MAX_MEM_ACC_LEVELS] = {MAX_VC, MAX_VC, MAX_VC};
-
- curr_level = c->osm_table[0].mem_acc_level;
- for (i = 0; i < c->num_entries; i++) {
- if (curr_level == MAX_MEM_ACC_LEVELS)
- break;
-
- if (c->osm_table[i].mem_acc_level != curr_level) {
- mem_acc_level_map[j++] =
- c->osm_table[i].virtual_corner;
- curr_level = c->osm_table[i].mem_acc_level;
- }
- }
-
if (c->secure_init) {
clk_osm_write_seq_reg(c,
c->pbases[OSM_BASE] + MEMACC_CROSSOVER_VC,
@@ -1069,13 +1056,8 @@
clk_osm_write_seq_reg(c, c->mem_acc_addr[2], DATA_MEM(50));
clk_osm_write_seq_reg(c, c->mem_acc_crossover_vc,
DATA_MEM(78));
- clk_osm_write_seq_reg(c, mem_acc_level_map[0], DATA_MEM(79));
- if (c == &perfcl_clk)
- clk_osm_write_seq_reg(c, c->mem_acc_threshold_vc,
- DATA_MEM(80));
- else
- clk_osm_write_seq_reg(c, mem_acc_level_map[1],
- DATA_MEM(80));
+ clk_osm_write_seq_reg(c, c->mem_acc_level_vc[0], DATA_MEM(79));
+ clk_osm_write_seq_reg(c, c->mem_acc_level_vc[1], DATA_MEM(80));
/*
* Note that DATA_MEM[81] -> DATA_MEM[89] values will be
* confirmed post-si. Use a value of 1 for DATA_MEM[89] and
@@ -1086,13 +1068,9 @@
scm_io_write(c->pbases[SEQ_BASE] + DATA_MEM(78),
c->mem_acc_crossover_vc);
scm_io_write(c->pbases[SEQ_BASE] + DATA_MEM(79),
- mem_acc_level_map[0]);
- if (c == &perfcl_clk)
- scm_io_write(c->pbases[SEQ_BASE] + DATA_MEM(80),
- c->mem_acc_threshold_vc);
- else
- scm_io_write(c->pbases[SEQ_BASE] + DATA_MEM(80),
- mem_acc_level_map[1]);
+ c->mem_acc_level_vc[0]);
+ scm_io_write(c->pbases[SEQ_BASE] + DATA_MEM(80),
+ c->mem_acc_level_vc[1]);
}
}
@@ -1669,7 +1647,8 @@
/* Program LVAL corresponding to first turbo VC */
for (i = 0; i < c->num_entries; i++) {
- if (c->osm_table[i].mem_acc_level == MAX_MEM_ACC_LEVELS) {
+ if (c->osm_table[i].virtual_corner ==
+ c->mem_acc_level_vc[1]) {
lval = c->osm_table[i].freq_data & GENMASK(7, 0);
break;
}
@@ -1876,6 +1855,7 @@
u32 val;
int core_num;
unsigned long flags;
+ u64 cycle_counter_ret;
struct clk_osm *parent, *c = logical_cpu_to_clk(cpu);
if (IS_ERR_OR_NULL(c)) {
@@ -1903,9 +1883,10 @@
c->total_cycle_counter += val - c->prev_cycle_counter;
c->prev_cycle_counter = val;
}
+ cycle_counter_ret = c->total_cycle_counter;
spin_unlock_irqrestore(&parent->lock, flags);
- return c->total_cycle_counter;
+ return cycle_counter_ret;
}
static void clk_osm_setup_cycle_counters(struct clk_osm *c)
@@ -2288,6 +2269,7 @@
{
struct device_node *of = pdev->dev.of_node;
u32 *array;
+ char memacc_str[40];
int rc = 0;
struct resource *res;
@@ -2507,6 +2489,36 @@
return -ENOMEM;
}
+ snprintf(memacc_str, ARRAY_SIZE(memacc_str),
+ "qcom,l3-memacc-level-vc-bin%d", l3_clk.speedbin);
+ rc = of_property_read_u32_array(of, memacc_str, l3_clk.mem_acc_level_vc,
+ MEM_ACC_LEVELS_LUT);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find %s property, rc=%d\n",
+ memacc_str, rc);
+ return rc;
+ }
+
+ snprintf(memacc_str, ARRAY_SIZE(memacc_str),
+ "qcom,pwrcl-memacc-level-vc-bin%d", pwrcl_clk.speedbin);
+ rc = of_property_read_u32_array(of, memacc_str,
+ pwrcl_clk.mem_acc_level_vc, MEM_ACC_LEVELS_LUT);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find %s property, rc=%d\n",
+ memacc_str, rc);
+ return rc;
+ }
+
+ snprintf(memacc_str, ARRAY_SIZE(memacc_str),
+ "qcom,perfcl-memacc-level-vc-bin%d", pwrcl_clk.speedbin);
+ rc = of_property_read_u32_array(of, memacc_str,
+ perfcl_clk.mem_acc_level_vc, MEM_ACC_LEVELS_LUT);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find %s property, rc=%d\n",
+ memacc_str, rc);
+ return rc;
+ }
+
l3_clk.secure_init = perfcl_clk.secure_init = pwrcl_clk.secure_init =
of_property_read_bool(pdev->dev.of_node, "qcom,osm-no-tz");
diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c
index ca7a34c..17b2403 100644
--- a/drivers/clk/qcom/gcc-sdm845.c
+++ b/drivers/clk/qcom/gcc-sdm845.c
@@ -873,17 +873,6 @@
{ }
};
-static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src_sdm845_v2[] = {
- F(400000, P_BI_TCXO, 12, 1, 4),
- F(9600000, P_BI_TCXO, 2, 0, 0),
- F(19200000, P_BI_TCXO, 1, 0, 0),
- F(25000000, P_GPLL0_OUT_EVEN, 12, 0, 0),
- F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0),
- F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0),
- F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0),
- { }
-};
-
static struct clk_rcg2 gcc_sdcc2_apps_clk_src = {
.cmd_rcgr = 0x1400c,
.mnd_width = 8,
@@ -1341,7 +1330,6 @@
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_aggre_noc_pcie_tbu_clk",
- .flags = CLK_IS_CRITICAL,
.ops = &clk_branch2_ops,
},
},
@@ -4013,19 +4001,12 @@
50000000;
gcc_qupv3_wrap1_s7_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] =
128000000;
- gcc_sdcc2_apps_clk_src.freq_tbl = ftbl_gcc_sdcc2_apps_clk_src_sdm845_v2;
- gcc_sdcc2_apps_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] =
- 200000000;
gcc_ufs_card_axi_clk_src.freq_tbl =
ftbl_gcc_ufs_card_axi_clk_src_sdm845_v2;
gcc_ufs_card_axi_clk_src.clkr.hw.init->rate_max[VDD_CX_HIGH] =
240000000;
gcc_ufs_phy_axi_clk_src.freq_tbl =
ftbl_gcc_ufs_card_axi_clk_src_sdm845_v2;
- gcc_aggre_noc_pcie_tbu_clk.clkr.hw.init = &(struct clk_init_data){
- .name = "gcc_aggre_noc_pcie_tbu_clk",
- .ops = &clk_branch2_ops,
- };
}
static int gcc_sdm845_fixup(struct platform_device *pdev)
@@ -4098,6 +4079,10 @@
regmap_update_bits(regmap, GCC_MMSS_MISC, 0x3, 0x3);
regmap_update_bits(regmap, GCC_GPU_MISC, 0x3, 0x3);
+ /* Keep this clock on all the time on SDM845 v1 */
+ if (of_device_is_compatible(pdev->dev.of_node, "qcom,gcc-sdm845"))
+ clk_prepare_enable(gcc_aggre_noc_pcie_tbu_clk.clkr.hw.clk);
+
/* DFS clock registration */
ret = qcom_cc_register_rcg_dfs(pdev, &gcc_sdm845_dfs_desc);
if (ret)
diff --git a/drivers/clk/qcom/gpucc-sdm845.c b/drivers/clk/qcom/gpucc-sdm845.c
index 5f1b1ef..4f50f9a 100644
--- a/drivers/clk/qcom/gpucc-sdm845.c
+++ b/drivers/clk/qcom/gpucc-sdm845.c
@@ -142,6 +142,11 @@
.frac = 0x2aaa,
};
+static const struct pll_config gpu_cc_pll1_config = {
+ .l = 0x1a,
+ .frac = 0xaaaa,
+};
+
static struct clk_alpha_pll gpu_cc_pll0 = {
.offset = 0x0,
.vco_table = fabia_vco,
@@ -185,6 +190,26 @@
},
};
+static struct clk_alpha_pll gpu_cc_pll1 = {
+ .offset = 0x100,
+ .vco_table = fabia_vco,
+ .num_vco = ARRAY_SIZE(fabia_vco),
+ .type = FABIA_PLL,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_pll1",
+ .parent_names = (const char *[]){ "bi_tcxo" },
+ .num_parents = 1,
+ .ops = &clk_fabia_pll_ops,
+ VDD_MX_FMAX_MAP4(
+ MIN, 615000000,
+ LOW, 1066000000,
+ LOW_L1, 1600000000,
+ NOMINAL, 2000000000),
+ },
+ },
+};
+
static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = {
F(19200000, P_BI_TCXO, 1, 0, 0),
F(200000000, P_GPLL0_OUT_MAIN_DIV, 1.5, 0, 0),
@@ -192,6 +217,13 @@
{ }
};
+static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src_sdm845_v2[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(200000000, P_GPLL0_OUT_MAIN_DIV, 1.5, 0, 0),
+ F(500000000, P_GPU_CC_PLL1_OUT_MAIN, 1, 0, 0),
+ { }
+};
+
static struct clk_rcg2 gpu_cc_gmu_clk_src = {
.cmd_rcgr = 0x1120,
.mnd_width = 0,
@@ -235,6 +267,18 @@
{ }
};
+static const struct freq_tbl ftbl_gpu_cc_gx_gfx3d_clk_src_sdm845_v2[] = {
+ F(180000000, P_CRC_DIV, 1, 0, 0),
+ F(257000000, P_CRC_DIV, 1, 0, 0),
+ F(342000000, P_CRC_DIV, 1, 0, 0),
+ F(414000000, P_CRC_DIV, 1, 0, 0),
+ F(520000000, P_CRC_DIV, 1, 0, 0),
+ F(596000000, P_CRC_DIV, 1, 0, 0),
+ F(670000000, P_CRC_DIV, 1, 0, 0),
+ F(710000000, P_CRC_DIV, 1, 0, 0),
+ { }
+};
+
static struct clk_rcg2 gpu_cc_gx_gfx3d_clk_src = {
.cmd_rcgr = 0x101c,
.mnd_width = 0,
@@ -517,6 +561,7 @@
[GPU_CC_PLL0_OUT_EVEN] = &gpu_cc_pll0_out_even.clkr,
[GPU_CC_GX_GFX3D_CLK_SRC] = &gpu_cc_gx_gfx3d_clk_src.clkr,
[GPU_CC_GX_GFX3D_CLK] = &gpu_cc_gx_gfx3d_clk.clkr,
+ [GPU_CC_PLL1] = NULL,
};
static const struct qcom_reset_map gpu_cc_sdm845_resets[] = {
@@ -553,16 +598,76 @@
static const struct of_device_id gpu_cc_sdm845_match_table[] = {
{ .compatible = "qcom,gpucc-sdm845" },
+ { .compatible = "qcom,gpucc-sdm845-v2" },
{ }
};
MODULE_DEVICE_TABLE(of, gpu_cc_sdm845_match_table);
static const struct of_device_id gpu_cc_gfx_sdm845_match_table[] = {
{ .compatible = "qcom,gfxcc-sdm845" },
+ { .compatible = "qcom,gfxcc-sdm845-v2" },
{},
};
MODULE_DEVICE_TABLE(of, gpu_cc_gfx_sdm845_match_table);
+static void gpu_cc_sdm845_fixup_sdm845v2(struct regmap *regmap)
+{
+ clk_fabia_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll1_config);
+ gpu_cc_sdm845_clocks[GPU_CC_PLL1] = &gpu_cc_pll1.clkr;
+ gpu_cc_gmu_clk_src.freq_tbl = ftbl_gpu_cc_gmu_clk_src_sdm845_v2;
+ gpu_cc_gmu_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 500000000;
+}
+
+static void gpu_cc_gfx_sdm845_fixup_sdm845v2(void)
+{
+ gpu_cc_gx_gfx3d_clk_src.freq_tbl =
+ ftbl_gpu_cc_gx_gfx3d_clk_src_sdm845_v2;
+ gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_MIN] = 180000000;
+ gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_LOWER] =
+ 257000000;
+ gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_LOW] = 342000000;
+ gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_LOW_L1] =
+ 414000000;
+ gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_NOMINAL] =
+ 520000000;
+ gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_NOMINAL_L1] =
+ 596000000;
+ gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_HIGH] = 675000000;
+ gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_HIGH_L1] =
+ 710000000;
+}
+
+static int gpu_cc_gfx_sdm845_fixup(struct platform_device *pdev)
+{
+ const char *compat = NULL;
+ int compatlen = 0;
+
+ compat = of_get_property(pdev->dev.of_node, "compatible", &compatlen);
+ if (!compat || (compatlen <= 0))
+ return -EINVAL;
+
+ if (!strcmp(compat, "qcom,gfxcc-sdm845-v2"))
+ gpu_cc_gfx_sdm845_fixup_sdm845v2();
+
+ return 0;
+}
+
+static int gpu_cc_sdm845_fixup(struct platform_device *pdev,
+ struct regmap *regmap)
+{
+ const char *compat = NULL;
+ int compatlen = 0;
+
+ compat = of_get_property(pdev->dev.of_node, "compatible", &compatlen);
+ if (!compat || (compatlen <= 0))
+ return -EINVAL;
+
+ if (!strcmp(compat, "qcom,gpucc-sdm845-v2"))
+ gpu_cc_sdm845_fixup_sdm845v2(regmap);
+
+ return 0;
+}
+
static int gpu_cc_gfx_sdm845_probe(struct platform_device *pdev)
{
struct regmap *regmap;
@@ -616,6 +721,12 @@
/* Avoid turning on the rail during clock registration */
vdd_gfx.skip_handoff = true;
+ ret = gpu_cc_gfx_sdm845_fixup(pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to do GFX clock fixup\n");
+ return ret;
+ }
+
clk_fabia_pll_configure(&gpu_cc_pll0, regmap, &gpu_cc_pll0_config);
ret = qcom_cc_really_probe(pdev, &gpu_cc_gfx_sdm845_desc, regmap);
@@ -668,6 +779,12 @@
return PTR_ERR(vdd_cx.regulator[0]);
}
+ ret = gpu_cc_sdm845_fixup(pdev, regmap);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to do GPU CC clock fixup\n");
+ return ret;
+ }
+
ret = qcom_cc_really_probe(pdev, &gpu_cc_sdm845_desc, regmap);
if (ret) {
dev_err(&pdev->dev, "Failed to register GPU CC clocks\n");
diff --git a/drivers/crypto/msm/compat_qcedev.c b/drivers/crypto/msm/compat_qcedev.c
index 0ca28be..d61b6f3 100644
--- a/drivers/crypto/msm/compat_qcedev.c
+++ b/drivers/crypto/msm/compat_qcedev.c
@@ -96,7 +96,6 @@
for (i = 0; i < QCEDEV_MAX_BUFFERS; i++) {
err |= get_user(vaddr, &vbuf32->src[i].vaddr);
- vbuf->src[i].vaddr = NULL;
err |= put_user(vaddr, (compat_uptr_t *)&vbuf->src[i].vaddr);
err |= get_user(len, &vbuf32->src[i].len);
err |= put_user(len, &vbuf->src[i].len);
@@ -104,7 +103,6 @@
for (i = 0; i < QCEDEV_MAX_BUFFERS; i++) {
err |= get_user(vaddr, &vbuf32->dst[i].vaddr);
- vbuf->dst[i].vaddr = NULL;
err |= put_user(vaddr, (compat_uptr_t *)&vbuf->dst[i].vaddr);
err |= get_user(len, &vbuf32->dst[i].len);
err |= put_user(len, &vbuf->dst[i].len);
@@ -122,7 +120,6 @@
for (i = 0; i < QCEDEV_MAX_BUFFERS; i++) {
err |= get_user(vaddr, (compat_uptr_t *)&vbuf->src[i].vaddr);
- vbuf32->src[i].vaddr = 0;
err |= put_user(vaddr, &vbuf32->src[i].vaddr);
err |= get_user(len, &vbuf->src[i].len);
err |= put_user(len, &vbuf32->src[i].len);
@@ -130,7 +127,6 @@
for (i = 0; i < QCEDEV_MAX_BUFFERS; i++) {
err |= get_user(vaddr, (compat_uptr_t *)&vbuf->dst[i].vaddr);
- vbuf32->dst[i].vaddr = 0;
err |= put_user(vaddr, &vbuf32->dst[i].vaddr);
err |= get_user(len, &vbuf->dst[i].len);
err |= put_user(len, &vbuf32->dst[i].len);
@@ -275,7 +271,6 @@
for (i = 0; i < QCEDEV_MAX_BUFFERS; i++) {
err |= get_user(vaddr, &data32->data[i].vaddr);
- data->data[i].vaddr = 0;
err |= put_user(vaddr, (compat_uptr_t *)&data->data[i].vaddr);
err |= get_user(len, &data32->data[i].len);
err |= put_user(len, &data->data[i].len);
@@ -294,7 +289,6 @@
err |= get_user(diglen, &data32->diglen);
err |= put_user(diglen, &data->diglen);
err |= get_user(authkey, &data32->authkey);
- data->authkey = NULL;
err |= put_user(authkey, (compat_uptr_t *)&data->authkey);
err |= get_user(authklen, &data32->authklen);
err |= put_user(authklen, &data->authklen);
@@ -321,7 +315,6 @@
for (i = 0; i < QCEDEV_MAX_BUFFERS; i++) {
err |= get_user(vaddr, (compat_uptr_t *)&data->data[i].vaddr);
- data32->data[i].vaddr = 0;
err |= put_user(vaddr, &data32->data[i].vaddr);
err |= get_user(len, &data->data[i].len);
err |= put_user(len, &data32->data[i].len);
@@ -340,7 +333,6 @@
err |= get_user(diglen, &data->diglen);
err |= put_user(diglen, &data32->diglen);
err |= get_user(authkey, (compat_uptr_t *)&data->authkey);
- data32->authkey = 0;
err |= put_user(authkey, &data32->authkey);
err |= get_user(authklen, &data->authklen);
err |= put_user(authklen, &data32->authklen);
diff --git a/drivers/crypto/msm/ice.c b/drivers/crypto/msm/ice.c
index b411726..6ed82ef 100644
--- a/drivers/crypto/msm/ice.c
+++ b/drivers/crypto/msm/ice.c
@@ -459,7 +459,7 @@
(ICE_REV(ice_dev->ice_hw_version, MINOR) >= 1))) {
reg = qcom_ice_readl(ice_dev, QCOM_ICE_REGS_BYPASS_STATUS);
if ((reg & 0x80000000) != 0x0) {
- pr_err("%s: Bypass failed for ice = %p",
+ pr_err("%s: Bypass failed for ice = %pK",
__func__, (void *)ice_dev);
WARN_ON(1);
}
@@ -485,7 +485,7 @@
}
ice_dev->ice_hw_version = rev;
- dev_info(ice_dev->pdev, "QC ICE %d.%d.%d device found @0x%p\n",
+ dev_info(ice_dev->pdev, "QC ICE %d.%d.%d device found @0x%pK\n",
maj_rev, min_rev, step_rev,
ice_dev->mmio);
@@ -1275,7 +1275,7 @@
goto out;
}
- pr_err("%s: =========== REGISTER DUMP (%p)===========\n",
+ pr_err("%s: =========== REGISTER DUMP (%pK)===========\n",
ice_dev->ice_instance_type, ice_dev);
pr_err("%s: ICE Control: 0x%08x | ICE Reset: 0x%08x\n",
@@ -1589,7 +1589,7 @@
struct ice_device *ice_dev = NULL;
if (!node) {
- pr_err("%s: invalid node %p", __func__, node);
+ pr_err("%s: invalid node %pK", __func__, node);
goto out;
}
@@ -1606,13 +1606,14 @@
list_for_each_entry(ice_dev, &ice_devices, list) {
if (ice_dev->pdev->of_node == node) {
- pr_info("%s: found ice device %p\n", __func__, ice_dev);
+ pr_info("%s: found ice device %pK\n", __func__,
+ ice_dev);
break;
}
}
ice_pdev = to_platform_device(ice_dev->pdev);
- pr_info("%s: matching platform device %p\n", __func__, ice_pdev);
+ pr_info("%s: matching platform device %pK\n", __func__, ice_pdev);
out:
return ice_pdev;
}
@@ -1650,7 +1651,7 @@
}
ret = regulator_enable(ice_dev->reg);
if (ret) {
- pr_err("%s:%p: Could not enable regulator\n",
+ pr_err("%s:%pK: Could not enable regulator\n",
__func__, ice_dev);
goto out;
}
@@ -1658,7 +1659,7 @@
/* Setup Clocks */
if (qcom_ice_enable_clocks(ice_dev, true)) {
- pr_err("%s:%p:%s Could not enable clocks\n", __func__,
+ pr_err("%s:%pK:%s Could not enable clocks\n", __func__,
ice_dev, ice_dev->ice_instance_type);
goto out_reg;
}
@@ -1670,7 +1671,7 @@
ret = qcom_ice_set_bus_vote(ice_dev, vote);
if (ret) {
- pr_err("%s:%p: failed %d\n", __func__, ice_dev, ret);
+ pr_err("%s:%pK: failed %d\n", __func__, ice_dev, ret);
goto out_clocks;
}
@@ -1702,19 +1703,19 @@
/* Setup Bus Vote */
vote = qcom_ice_get_bus_vote(ice_dev, "MIN");
if (vote < 0) {
- pr_err("%s:%p: Unable to get bus vote\n", __func__, ice_dev);
+ pr_err("%s:%pK: Unable to get bus vote\n", __func__, ice_dev);
goto out_disable_clocks;
}
ret = qcom_ice_set_bus_vote(ice_dev, vote);
if (ret)
- pr_err("%s:%p: failed %d\n", __func__, ice_dev, ret);
+ pr_err("%s:%pK: failed %d\n", __func__, ice_dev, ret);
out_disable_clocks:
/* Setup Clocks */
if (qcom_ice_enable_clocks(ice_dev, false))
- pr_err("%s:%p:%s Could not disable clocks\n", __func__,
+ pr_err("%s:%pK:%s Could not disable clocks\n", __func__,
ice_dev, ice_dev->ice_instance_type);
/* Setup Regulator */
@@ -1725,7 +1726,7 @@
}
ret = regulator_disable(ice_dev->reg);
if (ret) {
- pr_err("%s:%p: Could not disable regulator\n",
+ pr_err("%s:%pK: Could not disable regulator\n",
__func__, ice_dev);
goto out;
}
diff --git a/drivers/crypto/msm/ota_crypto.c b/drivers/crypto/msm/ota_crypto.c
index 3a2a51d..d477815 100644
--- a/drivers/crypto/msm/ota_crypto.c
+++ b/drivers/crypto/msm/ota_crypto.c
@@ -172,7 +172,7 @@
podev = file->private_data;
if (podev != NULL && podev->magic != OTA_MAGIC) {
- pr_err("%s: invalid handle %p\n",
+ pr_err("%s: invalid handle %pK\n",
__func__, podev);
}
@@ -440,7 +440,7 @@
podev = file->private_data;
if (podev == NULL || podev->magic != OTA_MAGIC) {
- pr_err("%s: invalid handle %p\n",
+ pr_err("%s: invalid handle %pK\n",
__func__, podev);
return -ENOENT;
}
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index 82a316b..35d7542 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -1164,7 +1164,7 @@
#define QCE_WRITE_REG(val, addr) \
{ \
- pr_info(" [0x%p] 0x%x\n", addr, (uint32_t)val); \
+ pr_info(" [0x%pK] 0x%x\n", addr, (uint32_t)val); \
writel_relaxed(val, addr); \
}
@@ -2160,6 +2160,10 @@
pce_sps_data = &preq_info->ce_sps;
qce_callback = preq_info->qce_cb;
areq = (struct ahash_request *) preq_info->areq;
+ if (!areq) {
+ pr_err("sha operation error. areq is NULL\n");
+ return -ENXIO;
+ }
qce_dma_unmap_sg(pce_dev->pdev, areq->src, preq_info->src_nents,
DMA_TO_DEVICE);
memcpy(digest, (char *)(&pce_sps_data->result->auth_iv[0]),
@@ -2735,7 +2739,7 @@
sps_event->callback = NULL;
}
- pr_debug("success, %s : pipe_handle=0x%lx, desc fifo base (phy) = 0x%p\n",
+ pr_debug("success, %s : pipe_handle=0x%lx, desc fifo base (phy) = 0x%pK\n",
is_producer ? "PRODUCER(RX/OUT)" : "CONSUMER(TX/IN)",
(uintptr_t)sps_pipe_info, &sps_connect_info->desc.phys_base);
goto out;
@@ -2897,7 +2901,7 @@
bam.ipc_loglevel = QCE_BAM_DEFAULT_IPC_LOGLVL;
bam.options |= SPS_BAM_CACHED_WP;
pr_debug("bam physical base=0x%lx\n", (uintptr_t)bam.phys_addr);
- pr_debug("bam virtual base=0x%p\n", bam.virt_addr);
+ pr_debug("bam virtual base=0x%pK\n", bam.virt_addr);
/* Register CE Peripheral BAM device to SPS driver */
rc = sps_register_bam_device(&bam, &pbam->handle);
@@ -2972,7 +2976,7 @@
request_index++;
if (request_index >= MAX_QCE_BAM_REQ)
request_index = 0;
- if (xchg(&pce_dev->ce_request_info[request_index].
+ if (atomic_xchg(&pce_dev->ce_request_info[request_index].
in_use, true) == false) {
pce_dev->ce_request_index = request_index;
return request_index;
@@ -2988,7 +2992,8 @@
bool is_complete)
{
pce_dev->ce_request_info[req_info].xfer_type = QCE_XFER_TYPE_LAST;
- if (xchg(&pce_dev->ce_request_info[req_info].in_use, false) == true) {
+ if (atomic_xchg(&pce_dev->ce_request_info[req_info].in_use,
+ false) == true) {
if (req_info < MAX_QCE_BAM_REQ && is_complete)
atomic_dec(&pce_dev->no_of_queued_req);
} else
@@ -3000,7 +3005,7 @@
phys_addr_t addr =
DESC_FULL_ADDR((phys_addr_t) notify->data.transfer.iovec.flags,
notify->data.transfer.iovec.addr);
- pr_debug("sps ev_id=%d, addr=0x%pa, size=0x%x, flags=0x%x user=0x%p\n",
+ pr_debug("sps ev_id=%d, addr=0x%pa, size=0x%x, flags=0x%x user=0x%pK\n",
notify->event_id, &addr,
notify->data.transfer.iovec.size,
notify->data.transfer.iovec.flags,
@@ -4612,7 +4617,7 @@
{
int ret = 0;
- if (!(xchg(&pce_dev->ce_request_info[DUMMY_REQ_INDEX].
+ if (!(atomic_xchg(&pce_dev->ce_request_info[DUMMY_REQ_INDEX].
in_use, true) == false))
return -EBUSY;
ret = qce_process_sha_req(pce_dev, NULL);
@@ -6016,7 +6021,7 @@
}
for (i = 0; i < MAX_QCE_ALLOC_BAM_REQ; i++)
- pce_dev->ce_request_info[i].in_use = false;
+ atomic_set(&pce_dev->ce_request_info[i].in_use, false);
pce_dev->ce_request_index = 0;
pce_dev->memsize = 10 * PAGE_SIZE * MAX_QCE_ALLOC_BAM_REQ;
@@ -6194,12 +6199,13 @@
void qce_dump_req(void *handle)
{
int i;
+ bool req_in_use;
struct qce_device *pce_dev = (struct qce_device *)handle;
for (i = 0; i < MAX_QCE_BAM_REQ; i++) {
- pr_info("qce_dump_req %d %d\n", i,
- pce_dev->ce_request_info[i].in_use);
- if (pce_dev->ce_request_info[i].in_use == true)
+ req_in_use = atomic_read(&pce_dev->ce_request_info[i].in_use);
+ pr_info("qce_dump_req %d %d\n", i, req_in_use);
+ if (req_in_use == true)
_qce_dump_descr_fifos(pce_dev, i);
}
}
diff --git a/drivers/crypto/msm/qce50.h b/drivers/crypto/msm/qce50.h
index 0e60bd2..ab0d21d 100644
--- a/drivers/crypto/msm/qce50.h
+++ b/drivers/crypto/msm/qce50.h
@@ -214,7 +214,7 @@
};
struct ce_request_info {
- bool in_use;
+ atomic_t in_use;
bool in_prog;
enum qce_xfer_type_enum xfer_type;
struct ce_sps_data ce_sps;
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index 5d6e0c2..9f126b3 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -57,6 +57,7 @@
static DEFINE_MUTEX(send_cmd_lock);
static DEFINE_MUTEX(qcedev_sent_bw_req);
+static DEFINE_MUTEX(hash_access_lock);
static int qcedev_control_clocks(struct qcedev_control *podev, bool enable)
{
@@ -269,7 +270,7 @@
handle = file->private_data;
podev = handle->cntl;
if (podev != NULL && podev->magic != QCEDEV_MAGIC) {
- pr_err("%s: invalid handle %p\n",
+ pr_err("%s: invalid handle %pK\n",
__func__, podev);
}
kzfree(handle);
@@ -1657,7 +1658,7 @@
podev = handle->cntl;
qcedev_areq.handle = handle;
if (podev == NULL || podev->magic != QCEDEV_MAGIC) {
- pr_err("%s: invalid handle %p\n",
+ pr_err("%s: invalid handle %pK\n",
__func__, podev);
return -ENOENT;
}
@@ -1699,12 +1700,18 @@
(void __user *)arg,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
- if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev))
+ mutex_lock(&hash_access_lock);
+ if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev)) {
+ mutex_unlock(&hash_access_lock);
return -EINVAL;
+ }
qcedev_areq.op_type = QCEDEV_CRYPTO_OPER_SHA;
err = qcedev_hash_init(&qcedev_areq, handle, &sg_src);
- if (err)
+ if (err) {
+ mutex_unlock(&hash_access_lock);
return err;
+ }
+ mutex_unlock(&hash_access_lock);
if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
@@ -1722,32 +1729,42 @@
(void __user *)arg,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
- if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev))
+ mutex_lock(&hash_access_lock);
+ if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev)) {
+ mutex_unlock(&hash_access_lock);
return -EINVAL;
+ }
qcedev_areq.op_type = QCEDEV_CRYPTO_OPER_SHA;
if (qcedev_areq.sha_op_req.alg == QCEDEV_ALG_AES_CMAC) {
err = qcedev_hash_cmac(&qcedev_areq, handle, &sg_src);
- if (err)
+ if (err) {
+ mutex_unlock(&hash_access_lock);
return err;
+ }
} else {
if (handle->sha_ctxt.init_done == false) {
pr_err("%s Init was not called\n", __func__);
+ mutex_unlock(&hash_access_lock);
return -EINVAL;
}
err = qcedev_hash_update(&qcedev_areq, handle, &sg_src);
- if (err)
+ if (err) {
+ mutex_unlock(&hash_access_lock);
return err;
+ }
}
if (handle->sha_ctxt.diglen > QCEDEV_MAX_SHA_DIGEST) {
pr_err("Invalid sha_ctxt.diglen %d\n",
handle->sha_ctxt.diglen);
+ mutex_unlock(&hash_access_lock);
return -EINVAL;
}
memcpy(&qcedev_areq.sha_op_req.digest[0],
&handle->sha_ctxt.digest[0],
handle->sha_ctxt.diglen);
+ mutex_unlock(&hash_access_lock);
if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
@@ -1764,16 +1781,22 @@
(void __user *)arg,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
- if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev))
+ mutex_lock(&hash_access_lock);
+ if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev)) {
+ mutex_unlock(&hash_access_lock);
return -EINVAL;
+ }
qcedev_areq.op_type = QCEDEV_CRYPTO_OPER_SHA;
err = qcedev_hash_final(&qcedev_areq, handle);
- if (err)
+ if (err) {
+ mutex_unlock(&hash_access_lock);
return err;
+ }
qcedev_areq.sha_op_req.diglen = handle->sha_ctxt.diglen;
memcpy(&qcedev_areq.sha_op_req.digest[0],
&handle->sha_ctxt.digest[0],
handle->sha_ctxt.diglen);
+ mutex_unlock(&hash_access_lock);
if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
@@ -1788,20 +1811,28 @@
(void __user *)arg,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
- if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev))
+ mutex_lock(&hash_access_lock);
+ if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev)) {
+ mutex_unlock(&hash_access_lock);
return -EINVAL;
+ }
qcedev_areq.op_type = QCEDEV_CRYPTO_OPER_SHA;
qcedev_hash_init(&qcedev_areq, handle, &sg_src);
err = qcedev_hash_update(&qcedev_areq, handle, &sg_src);
- if (err)
+ if (err) {
+ mutex_unlock(&hash_access_lock);
return err;
+ }
err = qcedev_hash_final(&qcedev_areq, handle);
- if (err)
+ if (err) {
+ mutex_unlock(&hash_access_lock);
return err;
+ }
qcedev_areq.sha_op_req.diglen = handle->sha_ctxt.diglen;
memcpy(&qcedev_areq.sha_op_req.digest[0],
&handle->sha_ctxt.digest[0],
handle->sha_ctxt.diglen);
+ mutex_unlock(&hash_access_lock);
if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index b979fb9..b3269a6 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -265,7 +265,7 @@
preq->arsp = NULL;
/* free req */
if (xchg(&preq->in_use, false) == false)
- pr_warn("request info %p free already\n", preq);
+ pr_warn("request info %pK free already\n", preq);
else
atomic_dec(&pce->req_count);
}
@@ -1759,7 +1759,7 @@
}
#ifdef QCRYPTO_DEBUG
- dev_info(&pengine->pdev->dev, "_qce_ahash_complete: %p ret %d\n",
+ dev_info(&pengine->pdev->dev, "_qce_ahash_complete: %pK ret %d\n",
areq, ret);
#endif
if (digest) {
@@ -1818,7 +1818,7 @@
}
#ifdef QCRYPTO_DEBUG
- dev_info(&pengine->pdev->dev, "_qce_ablk_cipher_complete: %p ret %d\n",
+ dev_info(&pengine->pdev->dev, "_qce_ablk_cipher_complete: %pK ret %d\n",
areq, ret);
#endif
if (iv)
@@ -2520,7 +2520,7 @@
WARN_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
#ifdef QCRYPTO_DEBUG
- dev_info(&ctx->pengine->pdev->dev, "_qcrypto_enc_aes_ecb: %p\n", req);
+ dev_info(&ctx->pengine->pdev->dev, "_qcrypto_enc_aes_ecb: %pK\n", req);
#endif
if ((ctx->enc_key_len == AES_KEYSIZE_192) &&
@@ -2550,7 +2550,7 @@
WARN_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
#ifdef QCRYPTO_DEBUG
- dev_info(&ctx->pengine->pdev->dev, "_qcrypto_enc_aes_cbc: %p\n", req);
+ dev_info(&ctx->pengine->pdev->dev, "_qcrypto_enc_aes_cbc: %pK\n", req);
#endif
if ((ctx->enc_key_len == AES_KEYSIZE_192) &&
@@ -2580,7 +2580,7 @@
WARN_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
#ifdef QCRYPTO_DEBUG
- dev_info(&ctx->pengine->pdev->dev, "_qcrypto_enc_aes_ctr: %p\n", req);
+ dev_info(&ctx->pengine->pdev->dev, "_qcrypto_enc_aes_ctr: %pK\n", req);
#endif
if ((ctx->enc_key_len == AES_KEYSIZE_192) &&
@@ -2768,7 +2768,7 @@
WARN_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
#ifdef QCRYPTO_DEBUG
- dev_info(&ctx->pengine->pdev->dev, "_qcrypto_dec_aes_ecb: %p\n", req);
+ dev_info(&ctx->pengine->pdev->dev, "_qcrypto_dec_aes_ecb: %pK\n", req);
#endif
if ((ctx->enc_key_len == AES_KEYSIZE_192) &&
@@ -2798,7 +2798,7 @@
WARN_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
#ifdef QCRYPTO_DEBUG
- dev_info(&ctx->pengine->pdev->dev, "_qcrypto_dec_aes_cbc: %p\n", req);
+ dev_info(&ctx->pengine->pdev->dev, "_qcrypto_dec_aes_cbc: %pK\n", req);
#endif
if ((ctx->enc_key_len == AES_KEYSIZE_192) &&
@@ -2828,7 +2828,7 @@
WARN_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
#ifdef QCRYPTO_DEBUG
- dev_info(&ctx->pengine->pdev->dev, "_qcrypto_dec_aes_ctr: %p\n", req);
+ dev_info(&ctx->pengine->pdev->dev, "_qcrypto_dec_aes_ctr: %pK\n", req);
#endif
if ((ctx->enc_key_len == AES_KEYSIZE_192) &&
@@ -3394,7 +3394,7 @@
#ifdef QCRYPTO_DEBUG
dev_info(&ctx->pengine->pdev->dev,
- "_qcrypto_aead_encrypt_aes_cbc: %p\n", req);
+ "_qcrypto_aead_encrypt_aes_cbc: %pK\n", req);
#endif
rctx = aead_request_ctx(req);
@@ -3425,7 +3425,7 @@
#ifdef QCRYPTO_DEBUG
dev_info(&ctx->pengine->pdev->dev,
- "_qcrypto_aead_decrypt_aes_cbc: %p\n", req);
+ "_qcrypto_aead_decrypt_aes_cbc: %pK\n", req);
#endif
rctx = aead_request_ctx(req);
rctx->aead = 1;
@@ -4011,7 +4011,7 @@
unsigned int len)
{
struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(&tfm->base);
-
+ int ret = 0;
memset(&sha_ctx->authkey[0], 0, SHA1_BLOCK_SIZE);
if (len <= SHA1_BLOCK_SIZE) {
memcpy(&sha_ctx->authkey[0], key, len);
@@ -4019,16 +4019,19 @@
} else {
sha_ctx->alg = QCE_HASH_SHA1;
sha_ctx->diglen = SHA1_DIGEST_SIZE;
- _sha_hmac_setkey(tfm, key, len);
+ ret = _sha_hmac_setkey(tfm, key, len);
+ if (ret)
+ pr_err("SHA1 hmac setkey failed\n");
sha_ctx->authkey_in_len = SHA1_BLOCK_SIZE;
}
- return 0;
+ return ret;
}
static int _sha256_hmac_setkey(struct crypto_ahash *tfm, const u8 *key,
unsigned int len)
{
struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(&tfm->base);
+ int ret = 0;
memset(&sha_ctx->authkey[0], 0, SHA256_BLOCK_SIZE);
if (len <= SHA256_BLOCK_SIZE) {
@@ -4037,11 +4040,13 @@
} else {
sha_ctx->alg = QCE_HASH_SHA256;
sha_ctx->diglen = SHA256_DIGEST_SIZE;
- _sha_hmac_setkey(tfm, key, len);
+ ret = _sha_hmac_setkey(tfm, key, len);
+ if (ret)
+ pr_err("SHA256 hmac setkey failed\n");
sha_ctx->authkey_in_len = SHA256_BLOCK_SIZE;
}
- return 0;
+ return ret;
}
static int _sha_hmac_init_ihash(struct ahash_request *req,
diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig
index eeb7c49..55c484e 100644
--- a/drivers/gpu/drm/msm/Kconfig
+++ b/drivers/gpu/drm/msm/Kconfig
@@ -12,6 +12,7 @@
select QCOM_SCM
select SND_SOC_HDMI_CODEC if SND_SOC
select SYNC_FILE
+ select HDCP_QSEECOM
default y
help
DRM/KMS driver for MSM/snapdragon.
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index b698b65..b625996 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -3,6 +3,7 @@
ccflags-$(CONFIG_DRM_MSM_DSI_PLL) += -Idrivers/gpu/drm/msm/dsi
ccflags-y += -Idrivers/gpu/drm/msm/sde
ccflags-y += -Idrivers/media/platform/msm/sde/rotator
+ccflags-y += -Idrivers/gpu/drm/msm/hdmi
msm_drm-y := \
dp/dp_usbpd.o \
@@ -15,6 +16,7 @@
dp/dp_ctrl.o \
dp/dp_display.o \
dp/dp_drm.o \
+ dp/dp_hdcp2p2.o \
sde/sde_crtc.o \
sde/sde_encoder.o \
sde/sde_encoder_phys_vid.o \
@@ -36,6 +38,7 @@
sde/sde_hw_color_proc_v4.o \
sde/sde_hw_ad4.o \
sde_edid_parser.o \
+ sde_hdcp_1x.o
msm_drm-$(CONFIG_DRM_MSM_HDMI) += hdmi/hdmi.o \
hdmi/hdmi_audio.o \
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 5825ba8..914c408 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -17,196 +17,7 @@
#include <linux/delay.h>
#include "dp_catalog.h"
-
-/* DP_TX Registers */
-#define DP_HW_VERSION (0x00000000)
-#define DP_SW_RESET (0x00000010)
-#define DP_PHY_CTRL (0x00000014)
-#define DP_CLK_CTRL (0x00000018)
-#define DP_CLK_ACTIVE (0x0000001C)
-#define DP_INTR_STATUS (0x00000020)
-#define DP_INTR_STATUS2 (0x00000024)
-#define DP_INTR_STATUS3 (0x00000028)
-
-#define DP_DP_HPD_CTRL (0x00000200)
-#define DP_DP_HPD_INT_STATUS (0x00000204)
-#define DP_DP_HPD_INT_ACK (0x00000208)
-#define DP_DP_HPD_INT_MASK (0x0000020C)
-#define DP_DP_HPD_REFTIMER (0x00000218)
-#define DP_DP_HPD_EVENT_TIME_0 (0x0000021C)
-#define DP_DP_HPD_EVENT_TIME_1 (0x00000220)
-#define DP_AUX_CTRL (0x00000230)
-#define DP_AUX_DATA (0x00000234)
-#define DP_AUX_TRANS_CTRL (0x00000238)
-#define DP_TIMEOUT_COUNT (0x0000023C)
-#define DP_AUX_LIMITS (0x00000240)
-#define DP_AUX_STATUS (0x00000244)
-
-#define DP_DPCD_CP_IRQ (0x201)
-#define DP_DPCD_RXSTATUS (0x69493)
-
-#define DP_INTERRUPT_TRANS_NUM (0x000002A0)
-
-#define DP_MAINLINK_CTRL (0x00000400)
-#define DP_STATE_CTRL (0x00000404)
-#define DP_CONFIGURATION_CTRL (0x00000408)
-#define DP_SOFTWARE_MVID (0x00000410)
-#define DP_SOFTWARE_NVID (0x00000418)
-#define DP_TOTAL_HOR_VER (0x0000041C)
-#define DP_START_HOR_VER_FROM_SYNC (0x00000420)
-#define DP_HSYNC_VSYNC_WIDTH_POLARITY (0x00000424)
-#define DP_ACTIVE_HOR_VER (0x00000428)
-#define DP_MISC1_MISC0 (0x0000042C)
-#define DP_VALID_BOUNDARY (0x00000430)
-#define DP_VALID_BOUNDARY_2 (0x00000434)
-#define DP_LOGICAL2PHYSCIAL_LANE_MAPPING (0x00000438)
-
-#define DP_MAINLINK_READY (0x00000440)
-#define DP_MAINLINK_LEVELS (0x00000444)
-#define DP_TU (0x0000044C)
-
-#define DP_HBR2_COMPLIANCE_SCRAMBLER_RESET (0x00000454)
-#define DP_TEST_80BIT_CUSTOM_PATTERN_REG0 (0x000004C0)
-#define DP_TEST_80BIT_CUSTOM_PATTERN_REG1 (0x000004C4)
-#define DP_TEST_80BIT_CUSTOM_PATTERN_REG2 (0x000004C8)
-
-#define MMSS_DP_MISC1_MISC0 (0x0000042C)
-#define MMSS_DP_AUDIO_TIMING_GEN (0x00000480)
-#define MMSS_DP_AUDIO_TIMING_RBR_32 (0x00000484)
-#define MMSS_DP_AUDIO_TIMING_HBR_32 (0x00000488)
-#define MMSS_DP_AUDIO_TIMING_RBR_44 (0x0000048C)
-#define MMSS_DP_AUDIO_TIMING_HBR_44 (0x00000490)
-#define MMSS_DP_AUDIO_TIMING_RBR_48 (0x00000494)
-#define MMSS_DP_AUDIO_TIMING_HBR_48 (0x00000498)
-
-#define MMSS_DP_PSR_CRC_RG (0x00000554)
-#define MMSS_DP_PSR_CRC_B (0x00000558)
-
-#define MMSS_DP_AUDIO_CFG (0x00000600)
-#define MMSS_DP_AUDIO_STATUS (0x00000604)
-#define MMSS_DP_AUDIO_PKT_CTRL (0x00000608)
-#define MMSS_DP_AUDIO_PKT_CTRL2 (0x0000060C)
-#define MMSS_DP_AUDIO_ACR_CTRL (0x00000610)
-#define MMSS_DP_AUDIO_CTRL_RESET (0x00000614)
-
-#define MMSS_DP_SDP_CFG (0x00000628)
-#define MMSS_DP_SDP_CFG2 (0x0000062C)
-#define MMSS_DP_AUDIO_TIMESTAMP_0 (0x00000630)
-#define MMSS_DP_AUDIO_TIMESTAMP_1 (0x00000634)
-
-#define MMSS_DP_AUDIO_STREAM_0 (0x00000640)
-#define MMSS_DP_AUDIO_STREAM_1 (0x00000644)
-
-#define MMSS_DP_EXTENSION_0 (0x00000650)
-#define MMSS_DP_EXTENSION_1 (0x00000654)
-#define MMSS_DP_EXTENSION_2 (0x00000658)
-#define MMSS_DP_EXTENSION_3 (0x0000065C)
-#define MMSS_DP_EXTENSION_4 (0x00000660)
-#define MMSS_DP_EXTENSION_5 (0x00000664)
-#define MMSS_DP_EXTENSION_6 (0x00000668)
-#define MMSS_DP_EXTENSION_7 (0x0000066C)
-#define MMSS_DP_EXTENSION_8 (0x00000670)
-#define MMSS_DP_EXTENSION_9 (0x00000674)
-#define MMSS_DP_AUDIO_COPYMANAGEMENT_0 (0x00000678)
-#define MMSS_DP_AUDIO_COPYMANAGEMENT_1 (0x0000067C)
-#define MMSS_DP_AUDIO_COPYMANAGEMENT_2 (0x00000680)
-#define MMSS_DP_AUDIO_COPYMANAGEMENT_3 (0x00000684)
-#define MMSS_DP_AUDIO_COPYMANAGEMENT_4 (0x00000688)
-#define MMSS_DP_AUDIO_COPYMANAGEMENT_5 (0x0000068C)
-#define MMSS_DP_AUDIO_ISRC_0 (0x00000690)
-#define MMSS_DP_AUDIO_ISRC_1 (0x00000694)
-#define MMSS_DP_AUDIO_ISRC_2 (0x00000698)
-#define MMSS_DP_AUDIO_ISRC_3 (0x0000069C)
-#define MMSS_DP_AUDIO_ISRC_4 (0x000006A0)
-#define MMSS_DP_AUDIO_ISRC_5 (0x000006A4)
-#define MMSS_DP_AUDIO_INFOFRAME_0 (0x000006A8)
-#define MMSS_DP_AUDIO_INFOFRAME_1 (0x000006AC)
-#define MMSS_DP_AUDIO_INFOFRAME_2 (0x000006B0)
-
-#define MMSS_DP_GENERIC0_0 (0x00000700)
-#define MMSS_DP_GENERIC0_1 (0x00000704)
-#define MMSS_DP_GENERIC0_2 (0x00000708)
-#define MMSS_DP_GENERIC0_3 (0x0000070C)
-#define MMSS_DP_GENERIC0_4 (0x00000710)
-#define MMSS_DP_GENERIC0_5 (0x00000714)
-#define MMSS_DP_GENERIC0_6 (0x00000718)
-#define MMSS_DP_GENERIC0_7 (0x0000071C)
-#define MMSS_DP_GENERIC0_8 (0x00000720)
-#define MMSS_DP_GENERIC0_9 (0x00000724)
-#define MMSS_DP_GENERIC1_0 (0x00000728)
-#define MMSS_DP_GENERIC1_1 (0x0000072C)
-#define MMSS_DP_GENERIC1_2 (0x00000730)
-#define MMSS_DP_GENERIC1_3 (0x00000734)
-#define MMSS_DP_GENERIC1_4 (0x00000738)
-#define MMSS_DP_GENERIC1_5 (0x0000073C)
-#define MMSS_DP_GENERIC1_6 (0x00000740)
-#define MMSS_DP_GENERIC1_7 (0x00000744)
-#define MMSS_DP_GENERIC1_8 (0x00000748)
-#define MMSS_DP_GENERIC1_9 (0x0000074C)
-
-#define MMSS_DP_TIMING_ENGINE_EN (0x00000A10)
-#define MMSS_DP_ASYNC_FIFO_CONFIG (0x00000A88)
-
-/*DP PHY Register offsets */
-#define DP_PHY_REVISION_ID0 (0x00000000)
-#define DP_PHY_REVISION_ID1 (0x00000004)
-#define DP_PHY_REVISION_ID2 (0x00000008)
-#define DP_PHY_REVISION_ID3 (0x0000000C)
-
-#define DP_PHY_CFG (0x00000010)
-#define DP_PHY_PD_CTL (0x00000018)
-#define DP_PHY_MODE (0x0000001C)
-
-#define DP_PHY_AUX_CFG0 (0x00000020)
-#define DP_PHY_AUX_CFG1 (0x00000024)
-#define DP_PHY_AUX_CFG2 (0x00000028)
-#define DP_PHY_AUX_CFG3 (0x0000002C)
-#define DP_PHY_AUX_CFG4 (0x00000030)
-#define DP_PHY_AUX_CFG5 (0x00000034)
-#define DP_PHY_AUX_CFG6 (0x00000038)
-#define DP_PHY_AUX_CFG7 (0x0000003C)
-#define DP_PHY_AUX_CFG8 (0x00000040)
-#define DP_PHY_AUX_CFG9 (0x00000044)
-#define DP_PHY_AUX_INTERRUPT_MASK (0x00000048)
-#define DP_PHY_AUX_INTERRUPT_CLEAR (0x0000004C)
-
-#define DP_PHY_SPARE0 (0x00AC)
-
-#define TXn_TX_EMP_POST1_LVL (0x000C)
-#define TXn_TX_DRV_LVL (0x001C)
-
-#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN (0x004)
-
-/* DP MMSS_CC registers */
-#define MMSS_DP_LINK_CMD_RCGR (0x0138)
-#define MMSS_DP_LINK_CFG_RCGR (0x013C)
-#define MMSS_DP_PIXEL_M (0x0174)
-#define MMSS_DP_PIXEL_N (0x0178)
-
-/* DP HDCP 1.3 registers */
-#define DP_HDCP_CTRL (0x0A0)
-#define DP_HDCP_STATUS (0x0A4)
-#define DP_HDCP_SW_UPPER_AKSV (0x298)
-#define DP_HDCP_SW_LOWER_AKSV (0x29C)
-#define DP_HDCP_ENTROPY_CTRL0 (0x750)
-#define DP_HDCP_ENTROPY_CTRL1 (0x75C)
-#define DP_HDCP_SHA_STATUS (0x0C8)
-#define DP_HDCP_RCVPORT_DATA2_0 (0x0B0)
-#define DP_HDCP_RCVPORT_DATA3 (0x2A4)
-#define DP_HDCP_RCVPORT_DATA4 (0x2A8)
-#define DP_HDCP_RCVPORT_DATA5 (0x0C0)
-#define DP_HDCP_RCVPORT_DATA6 (0x0C4)
-
-#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_CTRL (0x024)
-#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_DATA (0x028)
-#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA0 (0x004)
-#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA1 (0x008)
-#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA7 (0x00C)
-#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA8 (0x010)
-#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA9 (0x014)
-#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA10 (0x018)
-#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA11 (0x01C)
-#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA12 (0x020)
+#include "dp_reg.h"
#define dp_read(offset) readl_relaxed((offset))
#define dp_write(offset, data) writel_relaxed((data), (offset))
@@ -424,6 +235,22 @@
}
/* controller related catalog functions */
+static u32 dp_catalog_ctrl_read_hdcp_status(struct dp_catalog_ctrl *ctrl)
+{
+ struct dp_catalog_private *catalog;
+ void __iomem *base;
+
+ if (!ctrl) {
+ pr_err("invalid input\n");
+ return -EINVAL;
+ }
+
+ dp_catalog_get_priv(ctrl);
+ base = catalog->io->ctrl_io.base;
+
+ return dp_read(base + DP_HDCP_STATUS);
+}
+
static void dp_catalog_ctrl_update_transfer_unit(struct dp_catalog_ctrl *ctrl)
{
struct dp_catalog_private *catalog;
@@ -917,6 +744,7 @@
.update_vx_px = dp_catalog_ctrl_update_vx_px,
.get_interrupt = dp_catalog_ctrl_get_interrupt,
.update_transfer_unit = dp_catalog_ctrl_update_transfer_unit,
+ .read_hdcp_status = dp_catalog_ctrl_read_hdcp_status,
};
struct dp_catalog_audio audio = {
.acr_ctrl = dp_catalog_audio_acr_ctrl,
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h b/drivers/gpu/drm/msm/dp/dp_catalog.h
index c9916c72..2bd6bfd 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.h
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
@@ -71,6 +71,7 @@
u8 p_level);
void (*get_interrupt)(struct dp_catalog_ctrl *ctrl);
void (*update_transfer_unit)(struct dp_catalog_ctrl *ctrl);
+ u32 (*read_hdcp_status)(struct dp_catalog_ctrl *ctrl);
};
struct dp_catalog_audio {
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index b45cf4d..e191c1a 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -20,6 +20,7 @@
#include <linux/debugfs.h>
#include <linux/component.h>
#include <linux/of_irq.h>
+#include <linux/hdcp_qseecom.h>
#include "msm_drv.h"
#include "dp_usbpd.h"
@@ -31,9 +32,25 @@
#include "dp_panel.h"
#include "dp_ctrl.h"
#include "dp_display.h"
+#include "sde_hdcp.h"
static struct dp_display *g_dp_display;
+struct dp_hdcp {
+ void *data;
+ struct sde_hdcp_ops *ops;
+
+ void *hdcp1;
+ void *hdcp2;
+
+ int enc_lvl;
+
+ bool auth_state;
+ bool hdcp1_present;
+ bool hdcp2_present;
+ bool feature_enabled;
+};
+
struct dp_display_private {
char *name;
int irq;
@@ -55,10 +72,16 @@
struct dp_link *link;
struct dp_panel *panel;
struct dp_ctrl *ctrl;
+ struct dp_hdcp hdcp;
struct dp_usbpd_cb usbpd_cb;
struct dp_display_mode mode;
struct dp_display dp_display;
+
+ struct workqueue_struct *hdcp_workqueue;
+ struct delayed_work hdcp_cb_work;
+ struct mutex hdcp_mutex;
+ int hdcp_status;
};
static const struct of_device_id dp_dt_match[] = {
@@ -66,6 +89,13 @@
{}
};
+static inline bool dp_display_is_hdcp_enabled(struct dp_display_private *dp)
+{
+ return dp->hdcp.feature_enabled &&
+ (dp->hdcp.hdcp1_present || dp->hdcp.hdcp2_present) &&
+ dp->hdcp.ops;
+}
+
static irqreturn_t dp_display_irq(int irq, void *dev_id)
{
struct dp_display_private *dp = dev_id;
@@ -81,6 +111,12 @@
/* DP aux isr */
dp->aux->isr(dp->aux);
+ /* HDCP isr */
+ if (dp_display_is_hdcp_enabled(dp) && dp->hdcp.ops->isr) {
+ if (dp->hdcp.ops->isr(dp->hdcp.data))
+ pr_err("dp_hdcp_isr failed\n");
+ }
+
return IRQ_HANDLED;
}
@@ -158,6 +194,213 @@
return 0;
}
+static void dp_display_hdcp_cb_work(struct work_struct *work)
+{
+ struct dp_display_private *dp;
+ struct delayed_work *dw = to_delayed_work(work);
+ struct sde_hdcp_ops *ops;
+ int rc = 0;
+ u32 hdcp_auth_state;
+
+ dp = container_of(dw, struct dp_display_private, hdcp_cb_work);
+
+ rc = dp->catalog->ctrl.read_hdcp_status(&dp->catalog->ctrl);
+ if (rc >= 0) {
+ hdcp_auth_state = (rc >> 20) & 0x3;
+ pr_debug("hdcp auth state %d\n", hdcp_auth_state);
+ }
+
+ ops = dp->hdcp.ops;
+
+ switch (dp->hdcp_status) {
+ case HDCP_STATE_AUTHENTICATING:
+ pr_debug("start authenticaton\n");
+
+ if (dp->hdcp.ops && dp->hdcp.ops->authenticate)
+ rc = dp->hdcp.ops->authenticate(dp->hdcp.data);
+
+ break;
+ case HDCP_STATE_AUTHENTICATED:
+ pr_debug("hdcp authenticated\n");
+ dp->hdcp.auth_state = true;
+ break;
+ case HDCP_STATE_AUTH_FAIL:
+ dp->hdcp.auth_state = false;
+
+ if (dp->power_on) {
+ pr_debug("Reauthenticating\n");
+ if (ops && ops->reauthenticate) {
+ rc = ops->reauthenticate(dp->hdcp.data);
+ if (rc)
+ pr_err("reauth failed rc=%d\n", rc);
+ }
+ } else {
+ pr_debug("not reauthenticating, cable disconnected\n");
+ }
+
+ break;
+ default:
+ break;
+ }
+}
+
+static void dp_display_notify_hdcp_status_cb(void *ptr,
+ enum sde_hdcp_states status)
+{
+ struct dp_display_private *dp = ptr;
+
+ if (!dp) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ dp->hdcp_status = status;
+
+ if (dp->dp_display.is_connected)
+ queue_delayed_work(dp->hdcp_workqueue, &dp->hdcp_cb_work, HZ/4);
+}
+
+static int dp_display_create_hdcp_workqueue(struct dp_display_private *dp)
+{
+ dp->hdcp_workqueue = create_workqueue("sdm_dp_hdcp");
+ if (IS_ERR_OR_NULL(dp->hdcp_workqueue)) {
+ pr_err("Error creating hdcp_workqueue\n");
+ return -EPERM;
+ }
+
+ INIT_DELAYED_WORK(&dp->hdcp_cb_work, dp_display_hdcp_cb_work);
+
+ return 0;
+}
+
+static void dp_display_destroy_hdcp_workqueue(struct dp_display_private *dp)
+{
+ if (dp->hdcp_workqueue)
+ destroy_workqueue(dp->hdcp_workqueue);
+}
+
+static void dp_display_update_hdcp_info(struct dp_display_private *dp)
+{
+ void *fd = NULL;
+ struct sde_hdcp_ops *ops = NULL;
+
+ if (!dp) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ if (!dp->hdcp.feature_enabled) {
+ pr_debug("feature not enabled\n");
+ return;
+ }
+
+ fd = dp->hdcp.hdcp2;
+ if (fd)
+ ops = sde_dp_hdcp2p2_start(fd);
+
+ if (ops && ops->feature_supported)
+ dp->hdcp.hdcp2_present = ops->feature_supported(fd);
+ else
+ dp->hdcp.hdcp2_present = false;
+
+ pr_debug("hdcp2p2: %s\n",
+ dp->hdcp.hdcp2_present ? "supported" : "not supported");
+
+ if (!dp->hdcp.hdcp2_present) {
+ dp->hdcp.hdcp1_present = hdcp1_check_if_supported_load_app();
+
+ if (dp->hdcp.hdcp1_present) {
+ fd = dp->hdcp.hdcp1;
+ ops = sde_hdcp_1x_start(fd);
+ }
+ }
+
+ pr_debug("hdcp1x: %s\n",
+ dp->hdcp.hdcp1_present ? "supported" : "not supported");
+
+ if (dp->hdcp.hdcp2_present || dp->hdcp.hdcp1_present) {
+ dp->hdcp.data = fd;
+ dp->hdcp.ops = ops;
+ } else {
+ dp->hdcp.data = NULL;
+ dp->hdcp.ops = NULL;
+ }
+}
+
+static void dp_display_deinitialize_hdcp(struct dp_display_private *dp)
+{
+ if (!dp) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ sde_dp_hdcp2p2_deinit(dp->hdcp.data);
+ dp_display_destroy_hdcp_workqueue(dp);
+ if (&dp->hdcp_mutex)
+ mutex_destroy(&dp->hdcp_mutex);
+}
+
+static int dp_display_initialize_hdcp(struct dp_display_private *dp)
+{
+ struct sde_hdcp_init_data hdcp_init_data;
+ struct resource *res;
+ int rc = 0;
+
+ if (!dp) {
+ pr_err("invalid input\n");
+ return -EINVAL;
+ }
+
+ mutex_init(&dp->hdcp_mutex);
+
+ rc = dp_display_create_hdcp_workqueue(dp);
+ if (rc) {
+ pr_err("Failed to create HDCP workqueue\n");
+ goto error;
+ }
+
+ res = platform_get_resource_byname(dp->pdev,
+ IORESOURCE_MEM, "dp_ctrl");
+ if (!res) {
+ pr_err("Error getting dp ctrl resource\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ hdcp_init_data.phy_addr = res->start;
+ hdcp_init_data.client_id = HDCP_CLIENT_DP;
+ hdcp_init_data.drm_aux = dp->aux->drm_aux;
+ hdcp_init_data.cb_data = (void *)dp;
+ hdcp_init_data.workq = dp->hdcp_workqueue;
+ hdcp_init_data.mutex = &dp->hdcp_mutex;
+ hdcp_init_data.sec_access = true;
+ hdcp_init_data.notify_status = dp_display_notify_hdcp_status_cb;
+ hdcp_init_data.core_io = &dp->parser->io.ctrl_io;
+ hdcp_init_data.qfprom_io = &dp->parser->io.qfprom_io;
+ hdcp_init_data.hdcp_io = &dp->parser->io.hdcp_io;
+ hdcp_init_data.revision = &dp->panel->link_info.revision;
+
+ dp->hdcp.hdcp1 = sde_hdcp_1x_init(&hdcp_init_data);
+ if (IS_ERR_OR_NULL(dp->hdcp.hdcp1)) {
+ pr_err("Error initializing HDCP 1.x\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ pr_debug("HDCP 1.3 initialized\n");
+
+ dp->hdcp.hdcp2 = sde_dp_hdcp2p2_init(&hdcp_init_data);
+ if (!IS_ERR_OR_NULL(dp->hdcp.hdcp2))
+ pr_debug("HDCP 2.2 initialized\n");
+
+ dp->hdcp.feature_enabled = true;
+
+ return 0;
+error:
+ dp_display_deinitialize_hdcp(dp);
+ return rc;
+}
+
static int dp_display_bind(struct device *dev, struct device *master,
void *data)
{
@@ -215,6 +458,12 @@
pr_err("Power client create failed\n");
goto end;
}
+
+ rc = dp_display_initialize_hdcp(dp);
+ if (rc) {
+ pr_err("HDCP initialization failed\n");
+ goto end;
+ }
end:
return rc;
}
@@ -240,6 +489,7 @@
(void)dp->panel->sde_edid_deregister(dp->panel);
(void)dp->aux->drm_aux_deregister(dp->aux);
(void)dp_display_debugfs_deinit(dp);
+ dp_display_deinitialize_hdcp(dp);
}
static const struct component_ops dp_display_comp_ops = {
@@ -313,6 +563,11 @@
/* cancel any pending request */
dp->ctrl->abort(dp->ctrl);
+ if (dp_display_is_hdcp_enabled(dp) && dp->hdcp.ops->off) {
+ cancel_delayed_work_sync(&dp->hdcp_cb_work);
+ dp->hdcp.ops->off(dp->hdcp.data);
+ }
+
dp->dp_display.is_connected = false;
drm_helper_hpd_irq_event(dp->dp_display.connector->dev);
@@ -408,6 +663,12 @@
if (dp->usbpd->hpd_irq) {
dp->hpd_irq_on = true;
+
+ if (dp_display_is_hdcp_enabled(dp) && dp->hdcp.ops->cp_irq) {
+ if (!dp->hdcp.ops->cp_irq(dp->hdcp.data))
+ goto end;
+ }
+
rc = dp->link->process_request(dp->link);
dp->hpd_irq_on = false;
if (!rc)
@@ -564,6 +825,16 @@
dp = container_of(dp_display, struct dp_display_private, dp_display);
complete_all(&dp->notification_comp);
+
+ dp_display_update_hdcp_info(dp);
+
+ if (dp_display_is_hdcp_enabled(dp)) {
+ cancel_delayed_work_sync(&dp->hdcp_cb_work);
+
+ dp->hdcp_status = HDCP_STATE_AUTHENTICATING;
+ queue_delayed_work(dp->hdcp_workqueue,
+ &dp->hdcp_cb_work, HZ / 2);
+ }
end:
return rc;
}
@@ -581,6 +852,14 @@
dp = container_of(dp_display, struct dp_display_private, dp_display);
+ if (dp_display_is_hdcp_enabled(dp)) {
+ dp->hdcp_status = HDCP_STATE_INACTIVE;
+
+ cancel_delayed_work_sync(&dp->hdcp_cb_work);
+ if (dp->hdcp.ops->off)
+ dp->hdcp.ops->off(dp->hdcp.data);
+ }
+
dp->ctrl->push_idle(dp->ctrl);
error:
return rc;
diff --git a/drivers/gpu/drm/msm/dp/dp_hdcp2p2.c b/drivers/gpu/drm/msm/dp/dp_hdcp2p2.c
new file mode 100644
index 0000000..061acee
--- /dev/null
+++ b/drivers/gpu/drm/msm/dp/dp_hdcp2p2.c
@@ -0,0 +1,925 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "[dp-hdcp2p2] %s: " fmt, __func__
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/stat.h>
+#include <linux/types.h>
+#include <linux/kthread.h>
+#include <linux/hdcp_qseecom.h>
+#include <drm/drm_dp_helper.h>
+
+#include "sde_hdcp.h"
+
+#define DP_INTR_STATUS2 (0x00000024)
+#define DP_INTR_STATUS3 (0x00000028)
+#define dp_read(offset) readl_relaxed((offset))
+#define dp_write(offset, data) writel_relaxed((data), (offset))
+
+enum dp_hdcp2p2_sink_status {
+ SINK_DISCONNECTED,
+ SINK_CONNECTED
+};
+
+enum dp_auth_status {
+ DP_HDCP_AUTH_STATUS_FAILURE,
+ DP_HDCP_AUTH_STATUS_SUCCESS
+};
+
+struct dp_hdcp2p2_ctrl {
+ atomic_t auth_state;
+ enum dp_hdcp2p2_sink_status sink_status; /* Is sink connected */
+ struct dp_hdcp2p2_interrupts *intr;
+ struct sde_hdcp_init_data init_data;
+ struct mutex mutex; /* mutex to protect access to ctrl */
+ struct mutex msg_lock; /* mutex to protect access to msg buffer */
+ struct mutex wakeup_mutex; /* mutex to protect access to wakeup call*/
+ struct sde_hdcp_ops *ops;
+ void *lib_ctx; /* Handle to HDCP 2.2 Trustzone library */
+ struct hdcp_txmtr_ops *lib; /* Ops for driver to call into TZ */
+ enum hdcp_wakeup_cmd wakeup_cmd;
+ enum dp_auth_status auth_status;
+
+ struct task_struct *thread;
+ struct kthread_worker worker;
+ struct kthread_work status;
+ struct kthread_work auth;
+ struct kthread_work send_msg;
+ struct kthread_work recv_msg;
+ struct kthread_work link;
+ char *msg_buf;
+ uint32_t send_msg_len; /* length of all parameters in msg */
+ uint32_t timeout;
+ uint32_t num_messages;
+ struct hdcp_msg_part msg_part[HDCP_MAX_MESSAGE_PARTS];
+ u8 sink_rx_status;
+ u8 rx_status;
+ char abort_mask;
+
+ bool cp_irq_done;
+ bool polling;
+};
+
+struct dp_hdcp2p2_int_set {
+ u32 interrupt;
+ char *name;
+ void (*func)(struct dp_hdcp2p2_ctrl *ctrl);
+};
+
+struct dp_hdcp2p2_interrupts {
+ u32 reg;
+ struct dp_hdcp2p2_int_set *int_set;
+};
+
+static inline bool dp_hdcp2p2_is_valid_state(struct dp_hdcp2p2_ctrl *ctrl)
+{
+ if (ctrl->wakeup_cmd == HDCP_WKUP_CMD_AUTHENTICATE)
+ return true;
+
+ if (atomic_read(&ctrl->auth_state) != HDCP_STATE_INACTIVE)
+ return true;
+
+ return false;
+}
+
+static int dp_hdcp2p2_copy_buf(struct dp_hdcp2p2_ctrl *ctrl,
+ struct hdcp_wakeup_data *data)
+{
+ int i = 0;
+
+ if (!data || !data->message_data)
+ return 0;
+
+ mutex_lock(&ctrl->msg_lock);
+
+ ctrl->timeout = data->timeout;
+ ctrl->num_messages = data->message_data->num_messages;
+ ctrl->send_msg_len = 0; /* Total len of all messages */
+
+ for (i = 0; i < ctrl->num_messages ; i++)
+ ctrl->send_msg_len += data->message_data->messages[i].length;
+
+ memcpy(ctrl->msg_part, data->message_data->messages,
+ sizeof(data->message_data->messages));
+
+ ctrl->rx_status = data->message_data->rx_status;
+ ctrl->abort_mask = data->abort_mask;
+
+ if (!data->send_msg_len) {
+ mutex_unlock(&ctrl->msg_lock);
+ return 0;
+ }
+
+ kzfree(ctrl->msg_buf);
+
+ ctrl->msg_buf = kzalloc(ctrl->send_msg_len, GFP_KERNEL);
+
+ if (!ctrl->msg_buf) {
+ mutex_unlock(&ctrl->msg_lock);
+ return -ENOMEM;
+ }
+
+ /* ignore first byte as it contains message id */
+ memcpy(ctrl->msg_buf, data->send_msg_buf + 1, ctrl->send_msg_len);
+
+ mutex_unlock(&ctrl->msg_lock);
+
+ return 0;
+}
+
+static int dp_hdcp2p2_wakeup(struct hdcp_wakeup_data *data)
+{
+ struct dp_hdcp2p2_ctrl *ctrl;
+ u32 const default_timeout_us = 500;
+
+ if (!data) {
+ pr_err("invalid input\n");
+ return -EINVAL;
+ }
+
+ ctrl = data->context;
+ if (!ctrl) {
+ pr_err("invalid ctrl\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&ctrl->wakeup_mutex);
+
+ ctrl->wakeup_cmd = data->cmd;
+
+ if (data->timeout)
+ ctrl->timeout = (data->timeout) * 2;
+ else
+ ctrl->timeout = default_timeout_us;
+
+ if (!dp_hdcp2p2_is_valid_state(ctrl)) {
+ pr_err("invalid state\n");
+ goto exit;
+ }
+
+ if (dp_hdcp2p2_copy_buf(ctrl, data))
+ goto exit;
+
+ if (ctrl->wakeup_cmd == HDCP_WKUP_CMD_STATUS_SUCCESS)
+ ctrl->auth_status = DP_HDCP_AUTH_STATUS_SUCCESS;
+ else if (ctrl->wakeup_cmd == HDCP_WKUP_CMD_STATUS_FAILED)
+ ctrl->auth_status = DP_HDCP_AUTH_STATUS_FAILURE;
+
+ switch (ctrl->wakeup_cmd) {
+ case HDCP_WKUP_CMD_SEND_MESSAGE:
+ kthread_queue_work(&ctrl->worker, &ctrl->send_msg);
+ break;
+ case HDCP_WKUP_CMD_RECV_MESSAGE:
+ kthread_queue_work(&ctrl->worker, &ctrl->recv_msg);
+ break;
+ case HDCP_WKUP_CMD_STATUS_SUCCESS:
+ case HDCP_WKUP_CMD_STATUS_FAILED:
+ kthread_queue_work(&ctrl->worker, &ctrl->status);
+ break;
+ case HDCP_WKUP_CMD_LINK_POLL:
+ if (ctrl->cp_irq_done)
+ kthread_queue_work(&ctrl->worker, &ctrl->recv_msg);
+ else
+ ctrl->polling = true;
+ break;
+ case HDCP_WKUP_CMD_AUTHENTICATE:
+ kthread_queue_work(&ctrl->worker, &ctrl->auth);
+ break;
+ default:
+ pr_err("invalid wakeup command %d\n", ctrl->wakeup_cmd);
+ }
+exit:
+ mutex_unlock(&ctrl->wakeup_mutex);
+
+ return 0;
+}
+
+static inline void dp_hdcp2p2_wakeup_lib(struct dp_hdcp2p2_ctrl *ctrl,
+ struct hdcp_lib_wakeup_data *data)
+{
+ int rc = 0;
+
+ if (ctrl && ctrl->lib && ctrl->lib->wakeup &&
+ data && (data->cmd != HDCP_LIB_WKUP_CMD_INVALID)) {
+ rc = ctrl->lib->wakeup(data);
+ if (rc)
+ pr_err("error sending %s to lib\n",
+ hdcp_lib_cmd_to_str(data->cmd));
+ }
+}
+
+static void dp_hdcp2p2_reset(struct dp_hdcp2p2_ctrl *ctrl)
+{
+ if (!ctrl) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ ctrl->sink_status = SINK_DISCONNECTED;
+ atomic_set(&ctrl->auth_state, HDCP_STATE_INACTIVE);
+}
+
+static void dp_hdcp2p2_set_interrupts(struct dp_hdcp2p2_ctrl *ctrl, bool enable)
+{
+ void __iomem *base = ctrl->init_data.core_io->base;
+ struct dp_hdcp2p2_interrupts *intr = ctrl->intr;
+
+ while (intr && intr->reg) {
+ struct dp_hdcp2p2_int_set *int_set = intr->int_set;
+ u32 interrupts = 0;
+
+ while (int_set && int_set->interrupt) {
+ interrupts |= int_set->interrupt;
+ int_set++;
+ }
+
+ if (enable)
+ dp_write(base + intr->reg,
+ dp_read(base + intr->reg) | interrupts);
+ else
+ dp_write(base + intr->reg,
+ dp_read(base + intr->reg) & ~interrupts);
+ intr++;
+ }
+}
+
+static void dp_hdcp2p2_off(void *input)
+{
+ struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input;
+ struct hdcp_wakeup_data cdata = {HDCP_WKUP_CMD_AUTHENTICATE};
+
+ if (!ctrl) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) {
+ pr_err("hdcp is off\n");
+ return;
+ }
+
+ dp_hdcp2p2_set_interrupts(ctrl, false);
+
+ dp_hdcp2p2_reset(ctrl);
+
+ kthread_flush_worker(&ctrl->worker);
+
+ cdata.context = input;
+ dp_hdcp2p2_wakeup(&cdata);
+}
+
+static int dp_hdcp2p2_authenticate(void *input)
+{
+ struct dp_hdcp2p2_ctrl *ctrl = input;
+ struct hdcp_wakeup_data cdata = {HDCP_WKUP_CMD_AUTHENTICATE};
+ int rc = 0;
+
+ kthread_flush_worker(&ctrl->worker);
+
+ dp_hdcp2p2_set_interrupts(ctrl, true);
+
+ ctrl->sink_status = SINK_CONNECTED;
+ atomic_set(&ctrl->auth_state, HDCP_STATE_AUTHENTICATING);
+
+ cdata.context = input;
+ dp_hdcp2p2_wakeup(&cdata);
+
+ return rc;
+}
+
+static int dp_hdcp2p2_reauthenticate(void *input)
+{
+ struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input;
+
+ if (!ctrl) {
+ pr_err("invalid input\n");
+ return -EINVAL;
+ }
+
+ dp_hdcp2p2_reset((struct dp_hdcp2p2_ctrl *)input);
+
+ return dp_hdcp2p2_authenticate(input);
+}
+
+static void dp_hdcp2p2_min_level_change(void *client_ctx,
+ int min_enc_level)
+{
+ struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)client_ctx;
+ struct hdcp_lib_wakeup_data cdata = {
+ HDCP_LIB_WKUP_CMD_QUERY_STREAM_TYPE};
+ bool enc_notify = true;
+ int enc_lvl;
+
+ if (!ctrl) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ switch (min_enc_level) {
+ case 0:
+ enc_lvl = HDCP_STATE_AUTH_ENC_NONE;
+ break;
+ case 1:
+ enc_lvl = HDCP_STATE_AUTH_ENC_1X;
+ break;
+ case 2:
+ enc_lvl = HDCP_STATE_AUTH_ENC_2P2;
+ break;
+ default:
+ enc_notify = false;
+ }
+
+ pr_debug("enc level changed %d\n", min_enc_level);
+
+ cdata.context = ctrl->lib_ctx;
+ dp_hdcp2p2_wakeup_lib(ctrl, &cdata);
+
+ if (enc_notify && ctrl->init_data.notify_status)
+ ctrl->init_data.notify_status(ctrl->init_data.cb_data, enc_lvl);
+}
+
+static void dp_hdcp2p2_auth_failed(struct dp_hdcp2p2_ctrl *ctrl)
+{
+ if (!ctrl) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ dp_hdcp2p2_set_interrupts(ctrl, false);
+
+ atomic_set(&ctrl->auth_state, HDCP_STATE_AUTH_FAIL);
+
+ /* notify DP about HDCP failure */
+ ctrl->init_data.notify_status(ctrl->init_data.cb_data,
+ HDCP_STATE_AUTH_FAIL);
+}
+
+static int dp_hdcp2p2_aux_read_message(struct dp_hdcp2p2_ctrl *ctrl,
+ u8 *buf, int size, int offset, u32 timeout)
+{
+ int const max_size = 16;
+ int rc = 0, read_size = 0, bytes_read = 0;
+
+ if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) {
+ pr_err("hdcp is off\n");
+ return -EINVAL;
+ }
+
+ do {
+ read_size = min(size, max_size);
+
+ bytes_read = drm_dp_dpcd_read(ctrl->init_data.drm_aux,
+ offset, buf, read_size);
+ if (bytes_read != read_size) {
+ pr_err("fail: offset(0x%x), size(0x%x), rc(0x%x)\n",
+ offset, read_size, bytes_read);
+ break;
+ }
+
+ buf += read_size;
+ offset += read_size;
+ size -= read_size;
+ } while (size > 0);
+
+ return rc;
+}
+
+static int dp_hdcp2p2_aux_write_message(struct dp_hdcp2p2_ctrl *ctrl,
+ u8 *buf, int size, uint offset, uint timeout)
+{
+ int const max_size = 16;
+ int rc = 0, write_size = 0, bytes_written = 0;
+
+ do {
+ write_size = min(size, max_size);
+
+ bytes_written = drm_dp_dpcd_write(ctrl->init_data.drm_aux,
+ offset, buf, write_size);
+ if (bytes_written != write_size) {
+ pr_err("fail: offset(0x%x), size(0x%x), rc(0x%x)\n",
+ offset, write_size, bytes_written);
+ break;
+ }
+
+ buf += write_size;
+ offset += write_size;
+ size -= write_size;
+ } while (size > 0);
+
+ return rc;
+}
+
+static bool dp_hdcp2p2_feature_supported(void *input)
+{
+ struct dp_hdcp2p2_ctrl *ctrl = input;
+ struct hdcp_txmtr_ops *lib = NULL;
+ bool supported = false;
+
+ if (!ctrl) {
+ pr_err("invalid input\n");
+ goto end;
+ }
+
+ lib = ctrl->lib;
+ if (!lib) {
+ pr_err("invalid lib ops data\n");
+ goto end;
+ }
+
+ if (lib->feature_supported)
+ supported = lib->feature_supported(
+ ctrl->lib_ctx);
+end:
+ return supported;
+}
+
+static void dp_hdcp2p2_send_msg_work(struct kthread_work *work)
+{
+ int rc = 0;
+ struct dp_hdcp2p2_ctrl *ctrl = container_of(work,
+ struct dp_hdcp2p2_ctrl, send_msg);
+ struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID};
+
+ if (!ctrl) {
+ pr_err("invalid input\n");
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ cdata.context = ctrl->lib_ctx;
+
+ if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) {
+ pr_err("hdcp is off\n");
+ goto exit;
+ }
+
+ mutex_lock(&ctrl->msg_lock);
+
+ rc = dp_hdcp2p2_aux_write_message(ctrl, ctrl->msg_buf,
+ ctrl->send_msg_len, ctrl->msg_part->offset,
+ ctrl->timeout);
+ if (rc) {
+ pr_err("Error sending msg to sink %d\n", rc);
+ mutex_unlock(&ctrl->msg_lock);
+ goto exit;
+ }
+
+ cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS;
+ cdata.timeout = ctrl->timeout;
+ mutex_unlock(&ctrl->msg_lock);
+
+exit:
+ if (rc == -ETIMEDOUT)
+ cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT;
+ else if (rc)
+ cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED;
+
+ dp_hdcp2p2_wakeup_lib(ctrl, &cdata);
+}
+
+static int dp_hdcp2p2_get_msg_from_sink(struct dp_hdcp2p2_ctrl *ctrl)
+{
+ int rc = 0;
+ char *recvd_msg_buf = NULL;
+ struct hdcp_lib_wakeup_data cdata = { HDCP_LIB_WKUP_CMD_INVALID };
+
+ cdata.context = ctrl->lib_ctx;
+
+ recvd_msg_buf = kzalloc(ctrl->send_msg_len, GFP_KERNEL);
+ if (!recvd_msg_buf) {
+ rc = -ENOMEM;
+ goto exit;
+ }
+
+ rc = dp_hdcp2p2_aux_read_message(ctrl, recvd_msg_buf,
+ ctrl->send_msg_len, ctrl->msg_part->offset,
+ ctrl->timeout);
+ if (rc) {
+ pr_err("error reading message %d\n", rc);
+ goto exit;
+ }
+
+ cdata.recvd_msg_buf = recvd_msg_buf;
+ cdata.recvd_msg_len = ctrl->send_msg_len;
+ cdata.timeout = ctrl->timeout;
+exit:
+ if (rc == -ETIMEDOUT)
+ cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT;
+ else if (rc)
+ cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED;
+ else
+ cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS;
+
+ dp_hdcp2p2_wakeup_lib(ctrl, &cdata);
+ kfree(recvd_msg_buf);
+
+ return rc;
+}
+
+static void dp_hdcp2p2_recv_msg_work(struct kthread_work *work)
+{
+ struct hdcp_lib_wakeup_data cdata = { HDCP_LIB_WKUP_CMD_INVALID };
+ struct dp_hdcp2p2_ctrl *ctrl = container_of(work,
+ struct dp_hdcp2p2_ctrl, recv_msg);
+
+ cdata.context = ctrl->lib_ctx;
+
+ if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) {
+ pr_err("hdcp is off\n");
+ return;
+ }
+
+ if (ctrl->rx_status) {
+ if (!ctrl->cp_irq_done) {
+ pr_debug("waiting for CP_IRQ\n");
+ ctrl->polling = true;
+ return;
+ }
+
+ if (ctrl->rx_status & ctrl->sink_rx_status) {
+ ctrl->cp_irq_done = false;
+ ctrl->sink_rx_status = 0;
+ ctrl->rx_status = 0;
+ }
+ }
+
+ dp_hdcp2p2_get_msg_from_sink(ctrl);
+}
+
+static void dp_hdcp2p2_auth_status_work(struct kthread_work *work)
+{
+ struct dp_hdcp2p2_ctrl *ctrl = container_of(work,
+ struct dp_hdcp2p2_ctrl, status);
+
+ if (!ctrl) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) {
+ pr_err("hdcp is off\n");
+ return;
+ }
+
+ if (ctrl->auth_status == DP_HDCP_AUTH_STATUS_SUCCESS) {
+ ctrl->init_data.notify_status(ctrl->init_data.cb_data,
+ HDCP_STATE_AUTHENTICATED);
+
+ atomic_set(&ctrl->auth_state, HDCP_STATE_AUTHENTICATED);
+ } else {
+ dp_hdcp2p2_auth_failed(ctrl);
+ }
+}
+
+static void dp_hdcp2p2_link_work(struct kthread_work *work)
+{
+ int rc = 0;
+ struct dp_hdcp2p2_ctrl *ctrl = container_of(work,
+ struct dp_hdcp2p2_ctrl, link);
+ struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID};
+
+ if (!ctrl) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ if (atomic_read(&ctrl->auth_state) == HDCP_STATE_AUTH_FAIL ||
+ atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) {
+ pr_err("invalid hdcp state\n");
+ return;
+ }
+
+ cdata.context = ctrl->lib_ctx;
+
+ if (ctrl->sink_rx_status & ctrl->abort_mask) {
+ if (ctrl->sink_rx_status & BIT(3))
+ pr_err("reauth_req set by sink\n");
+
+ if (ctrl->sink_rx_status & BIT(4))
+ pr_err("link failure reported by sink\n");
+
+ ctrl->sink_rx_status = 0;
+ ctrl->rx_status = 0;
+
+ rc = -ENOLINK;
+
+ cdata.cmd = HDCP_LIB_WKUP_CMD_LINK_FAILED;
+ atomic_set(&ctrl->auth_state, HDCP_STATE_AUTH_FAIL);
+ goto exit;
+ }
+
+ if (ctrl->polling && (ctrl->sink_rx_status & ctrl->rx_status)) {
+ ctrl->sink_rx_status = 0;
+ ctrl->rx_status = 0;
+
+ dp_hdcp2p2_get_msg_from_sink(ctrl);
+
+ ctrl->polling = false;
+ } else {
+ ctrl->cp_irq_done = true;
+ }
+exit:
+ if (rc)
+ dp_hdcp2p2_wakeup_lib(ctrl, &cdata);
+}
+
+static void dp_hdcp2p2_auth_work(struct kthread_work *work)
+{
+ struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID};
+ struct dp_hdcp2p2_ctrl *ctrl = container_of(work,
+ struct dp_hdcp2p2_ctrl, auth);
+
+ cdata.context = ctrl->lib_ctx;
+
+ if (atomic_read(&ctrl->auth_state) == HDCP_STATE_AUTHENTICATING)
+ cdata.cmd = HDCP_LIB_WKUP_CMD_START;
+ else
+ cdata.cmd = HDCP_LIB_WKUP_CMD_STOP;
+
+ dp_hdcp2p2_wakeup_lib(ctrl, &cdata);
+}
+
+static int dp_hdcp2p2_read_rx_status(struct dp_hdcp2p2_ctrl *ctrl,
+ u8 *rx_status)
+{
+ u32 const cp_irq_dpcd_offset = 0x201;
+ u32 const rxstatus_dpcd_offset = 0x69493;
+ ssize_t const bytes_to_read = 1;
+ ssize_t bytes_read = 0;
+ u8 buf = 0;
+ int rc = 0;
+ bool cp_irq = 0;
+
+ *rx_status = 0;
+
+ bytes_read = drm_dp_dpcd_read(ctrl->init_data.drm_aux,
+ cp_irq_dpcd_offset, &buf, bytes_to_read);
+ if (bytes_read != bytes_to_read) {
+ pr_err("cp irq read failed\n");
+ rc = bytes_read;
+ goto error;
+ }
+
+ cp_irq = buf & BIT(2);
+ pr_debug("cp_irq=0x%x\n", cp_irq);
+ buf = 0;
+
+ if (cp_irq) {
+ bytes_read = drm_dp_dpcd_read(ctrl->init_data.drm_aux,
+ rxstatus_dpcd_offset, &buf, bytes_to_read);
+ if (bytes_read != bytes_to_read) {
+ pr_err("rxstatus read failed\n");
+ rc = bytes_read;
+ goto error;
+ }
+ *rx_status = buf;
+ pr_debug("rx_status=0x%x\n", *rx_status);
+ }
+
+error:
+ return rc;
+}
+
+static int dp_hdcp2p2_cp_irq(void *input)
+{
+ int rc = 0;
+ struct dp_hdcp2p2_ctrl *ctrl = input;
+
+ if (!ctrl) {
+ pr_err("invalid input\n");
+ return -EINVAL;
+ }
+
+ if (atomic_read(&ctrl->auth_state) == HDCP_STATE_AUTH_FAIL ||
+ atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) {
+ pr_err("invalid hdcp state\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ ctrl->sink_rx_status = 0;
+ rc = dp_hdcp2p2_read_rx_status(ctrl, &ctrl->sink_rx_status);
+ if (rc) {
+ pr_err("failed to read rx status\n");
+ goto error;
+ }
+
+ pr_debug("sink_rx_status=0x%x\n", ctrl->sink_rx_status);
+
+ if (!ctrl->sink_rx_status) {
+ pr_debug("not a hdcp 2.2 irq\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ kthread_queue_work(&ctrl->worker, &ctrl->link);
+
+ return 0;
+error:
+ return rc;
+}
+
+static int dp_hdcp2p2_isr(void *input)
+{
+ struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input;
+ int rc = 0;
+ struct dss_io_data *io;
+ struct dp_hdcp2p2_interrupts *intr;
+ u32 hdcp_int_val = 0;
+
+ if (!ctrl || !ctrl->init_data.core_io) {
+ pr_err("invalid input\n");
+ rc = -EINVAL;
+ goto end;
+ }
+
+ io = ctrl->init_data.core_io;
+ intr = ctrl->intr;
+
+ while (intr && intr->reg) {
+ struct dp_hdcp2p2_int_set *int_set = intr->int_set;
+
+ hdcp_int_val = dp_read(io->base + intr->reg);
+
+ while (int_set && int_set->interrupt) {
+ if (hdcp_int_val & (int_set->interrupt >> 2)) {
+ pr_debug("%s\n", int_set->name);
+
+ if (int_set->func)
+ int_set->func(ctrl);
+
+ dp_write(io->base + intr->reg, hdcp_int_val |
+ (int_set->interrupt >> 1));
+ }
+ int_set++;
+ }
+ intr++;
+ }
+end:
+ return rc;
+}
+
+void sde_dp_hdcp2p2_deinit(void *input)
+{
+ struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input;
+ struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID};
+
+ if (!ctrl) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ cdata.cmd = HDCP_LIB_WKUP_CMD_STOP;
+ cdata.context = ctrl->lib_ctx;
+ dp_hdcp2p2_wakeup_lib(ctrl, &cdata);
+
+ kthread_stop(ctrl->thread);
+
+ mutex_destroy(&ctrl->mutex);
+ mutex_destroy(&ctrl->msg_lock);
+ mutex_destroy(&ctrl->wakeup_mutex);
+ kzfree(ctrl->msg_buf);
+ kfree(ctrl);
+}
+
+void *sde_dp_hdcp2p2_init(struct sde_hdcp_init_data *init_data)
+{
+ int rc;
+ struct dp_hdcp2p2_ctrl *ctrl;
+ static struct hdcp_txmtr_ops txmtr_ops;
+ struct hdcp_register_data register_data;
+ static struct sde_hdcp_ops ops = {
+ .isr = dp_hdcp2p2_isr,
+ .reauthenticate = dp_hdcp2p2_reauthenticate,
+ .authenticate = dp_hdcp2p2_authenticate,
+ .feature_supported = dp_hdcp2p2_feature_supported,
+ .off = dp_hdcp2p2_off,
+ .cp_irq = dp_hdcp2p2_cp_irq,
+ };
+
+ static struct hdcp_client_ops client_ops = {
+ .wakeup = dp_hdcp2p2_wakeup,
+ .notify_lvl_change = dp_hdcp2p2_min_level_change,
+ };
+ static struct dp_hdcp2p2_int_set int_set1[] = {
+ {BIT(17), "authentication successful", NULL},
+ {BIT(20), "authentication failed", NULL},
+ {BIT(24), "encryption enabled", NULL},
+ {BIT(27), "encryption disabled", NULL},
+ {0},
+ };
+ static struct dp_hdcp2p2_int_set int_set2[] = {
+ {BIT(2), "key fifo underflow", NULL},
+ {0},
+ };
+ static struct dp_hdcp2p2_interrupts intr[] = {
+ {DP_INTR_STATUS2, int_set1},
+ {DP_INTR_STATUS3, int_set2},
+ {0}
+ };
+
+ if (!init_data || !init_data->cb_data ||
+ !init_data->notify_status || !init_data->drm_aux) {
+ pr_err("invalid input\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
+ if (!ctrl)
+ return ERR_PTR(-ENOMEM);
+
+ ctrl->init_data = *init_data;
+ ctrl->lib = &txmtr_ops;
+ ctrl->msg_buf = NULL;
+
+ ctrl->sink_status = SINK_DISCONNECTED;
+ ctrl->intr = intr;
+
+ atomic_set(&ctrl->auth_state, HDCP_STATE_INACTIVE);
+
+ ctrl->ops = &ops;
+ mutex_init(&ctrl->mutex);
+ mutex_init(&ctrl->msg_lock);
+ mutex_init(&ctrl->wakeup_mutex);
+
+ register_data.hdcp_ctx = &ctrl->lib_ctx;
+ register_data.client_ops = &client_ops;
+ register_data.txmtr_ops = &txmtr_ops;
+ register_data.device_type = HDCP_TXMTR_DP;
+ register_data.client_ctx = ctrl;
+
+ rc = hdcp_library_register(®ister_data);
+ if (rc) {
+ pr_err("Unable to register with HDCP 2.2 library\n");
+ goto error;
+ }
+
+ kthread_init_worker(&ctrl->worker);
+
+ kthread_init_work(&ctrl->auth, dp_hdcp2p2_auth_work);
+ kthread_init_work(&ctrl->send_msg, dp_hdcp2p2_send_msg_work);
+ kthread_init_work(&ctrl->recv_msg, dp_hdcp2p2_recv_msg_work);
+ kthread_init_work(&ctrl->status, dp_hdcp2p2_auth_status_work);
+ kthread_init_work(&ctrl->link, dp_hdcp2p2_link_work);
+
+ ctrl->thread = kthread_run(kthread_worker_fn,
+ &ctrl->worker, "dp_hdcp2p2");
+
+ if (IS_ERR(ctrl->thread)) {
+ pr_err("unable to start DP hdcp2p2 thread\n");
+ rc = PTR_ERR(ctrl->thread);
+ ctrl->thread = NULL;
+ goto error;
+ }
+
+ return ctrl;
+error:
+ kfree(ctrl);
+ return ERR_PTR(rc);
+}
+
+static bool dp_hdcp2p2_supported(struct dp_hdcp2p2_ctrl *ctrl)
+{
+ u32 const rxcaps_dpcd_offset = 0x6921d;
+ ssize_t const bytes_to_read = 1;
+ ssize_t bytes_read = 0;
+ u8 buf = 0;
+
+ bytes_read = drm_dp_dpcd_read(ctrl->init_data.drm_aux,
+ rxcaps_dpcd_offset, &buf, bytes_to_read);
+ if (bytes_read != bytes_to_read) {
+ pr_err("RxCaps read failed\n");
+ goto error;
+ }
+
+ pr_debug("rxcaps 0x%x\n", buf);
+
+ if (buf & BIT(1))
+ return true;
+error:
+ return false;
+}
+
+struct sde_hdcp_ops *sde_dp_hdcp2p2_start(void *input)
+{
+ struct dp_hdcp2p2_ctrl *ctrl = input;
+
+ pr_debug("Checking sink capability\n");
+ if (dp_hdcp2p2_supported(ctrl))
+ return ctrl->ops;
+ else
+ return NULL;
+}
+
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c
index 5f25b2d..d4e33e9 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.c
+++ b/drivers/gpu/drm/msm/dp/dp_panel.c
@@ -84,7 +84,7 @@
{
struct drm_dp_link *link_info;
const u8 num_components = 3;
- u32 bpc, bpp, max_data_rate_khz, max_pclk_rate_khz;
+ u32 bpc = 0, bpp = 0, max_data_rate_khz = 0, max_pclk_rate_khz = 0;
if (!dp_panel) {
pr_err("invalid input\n");
diff --git a/drivers/gpu/drm/msm/dp/dp_reg.h b/drivers/gpu/drm/msm/dp/dp_reg.h
new file mode 100644
index 0000000..30377a0
--- /dev/null
+++ b/drivers/gpu/drm/msm/dp/dp_reg.h
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _DP_REG_H_
+#define _DP_REG_H_
+
+/* DP_TX Registers */
+#define DP_HW_VERSION (0x00000000)
+#define DP_SW_RESET (0x00000010)
+#define DP_PHY_CTRL (0x00000014)
+#define DP_CLK_CTRL (0x00000018)
+#define DP_CLK_ACTIVE (0x0000001C)
+#define DP_INTR_STATUS (0x00000020)
+#define DP_INTR_STATUS2 (0x00000024)
+#define DP_INTR_STATUS3 (0x00000028)
+
+#define DP_DP_HPD_CTRL (0x00000200)
+#define DP_DP_HPD_INT_STATUS (0x00000204)
+#define DP_DP_HPD_INT_ACK (0x00000208)
+#define DP_DP_HPD_INT_MASK (0x0000020C)
+#define DP_DP_HPD_REFTIMER (0x00000218)
+#define DP_DP_HPD_EVENT_TIME_0 (0x0000021C)
+#define DP_DP_HPD_EVENT_TIME_1 (0x00000220)
+#define DP_AUX_CTRL (0x00000230)
+#define DP_AUX_DATA (0x00000234)
+#define DP_AUX_TRANS_CTRL (0x00000238)
+#define DP_TIMEOUT_COUNT (0x0000023C)
+#define DP_AUX_LIMITS (0x00000240)
+#define DP_AUX_STATUS (0x00000244)
+
+#define DP_DPCD_CP_IRQ (0x201)
+#define DP_DPCD_RXSTATUS (0x69493)
+
+#define DP_INTERRUPT_TRANS_NUM (0x000002A0)
+
+#define DP_MAINLINK_CTRL (0x00000400)
+#define DP_STATE_CTRL (0x00000404)
+#define DP_CONFIGURATION_CTRL (0x00000408)
+#define DP_SOFTWARE_MVID (0x00000410)
+#define DP_SOFTWARE_NVID (0x00000418)
+#define DP_TOTAL_HOR_VER (0x0000041C)
+#define DP_START_HOR_VER_FROM_SYNC (0x00000420)
+#define DP_HSYNC_VSYNC_WIDTH_POLARITY (0x00000424)
+#define DP_ACTIVE_HOR_VER (0x00000428)
+#define DP_MISC1_MISC0 (0x0000042C)
+#define DP_VALID_BOUNDARY (0x00000430)
+#define DP_VALID_BOUNDARY_2 (0x00000434)
+#define DP_LOGICAL2PHYSCIAL_LANE_MAPPING (0x00000438)
+
+#define DP_MAINLINK_READY (0x00000440)
+#define DP_MAINLINK_LEVELS (0x00000444)
+#define DP_TU (0x0000044C)
+
+#define DP_HBR2_COMPLIANCE_SCRAMBLER_RESET (0x00000454)
+#define DP_TEST_80BIT_CUSTOM_PATTERN_REG0 (0x000004C0)
+#define DP_TEST_80BIT_CUSTOM_PATTERN_REG1 (0x000004C4)
+#define DP_TEST_80BIT_CUSTOM_PATTERN_REG2 (0x000004C8)
+
+#define MMSS_DP_MISC1_MISC0 (0x0000042C)
+#define MMSS_DP_AUDIO_TIMING_GEN (0x00000480)
+#define MMSS_DP_AUDIO_TIMING_RBR_32 (0x00000484)
+#define MMSS_DP_AUDIO_TIMING_HBR_32 (0x00000488)
+#define MMSS_DP_AUDIO_TIMING_RBR_44 (0x0000048C)
+#define MMSS_DP_AUDIO_TIMING_HBR_44 (0x00000490)
+#define MMSS_DP_AUDIO_TIMING_RBR_48 (0x00000494)
+#define MMSS_DP_AUDIO_TIMING_HBR_48 (0x00000498)
+
+#define MMSS_DP_PSR_CRC_RG (0x00000554)
+#define MMSS_DP_PSR_CRC_B (0x00000558)
+
+#define MMSS_DP_AUDIO_CFG (0x00000600)
+#define MMSS_DP_AUDIO_STATUS (0x00000604)
+#define MMSS_DP_AUDIO_PKT_CTRL (0x00000608)
+#define MMSS_DP_AUDIO_PKT_CTRL2 (0x0000060C)
+#define MMSS_DP_AUDIO_ACR_CTRL (0x00000610)
+#define MMSS_DP_AUDIO_CTRL_RESET (0x00000614)
+
+#define MMSS_DP_SDP_CFG (0x00000628)
+#define MMSS_DP_SDP_CFG2 (0x0000062C)
+#define MMSS_DP_AUDIO_TIMESTAMP_0 (0x00000630)
+#define MMSS_DP_AUDIO_TIMESTAMP_1 (0x00000634)
+
+#define MMSS_DP_AUDIO_STREAM_0 (0x00000640)
+#define MMSS_DP_AUDIO_STREAM_1 (0x00000644)
+
+#define MMSS_DP_EXTENSION_0 (0x00000650)
+#define MMSS_DP_EXTENSION_1 (0x00000654)
+#define MMSS_DP_EXTENSION_2 (0x00000658)
+#define MMSS_DP_EXTENSION_3 (0x0000065C)
+#define MMSS_DP_EXTENSION_4 (0x00000660)
+#define MMSS_DP_EXTENSION_5 (0x00000664)
+#define MMSS_DP_EXTENSION_6 (0x00000668)
+#define MMSS_DP_EXTENSION_7 (0x0000066C)
+#define MMSS_DP_EXTENSION_8 (0x00000670)
+#define MMSS_DP_EXTENSION_9 (0x00000674)
+#define MMSS_DP_AUDIO_COPYMANAGEMENT_0 (0x00000678)
+#define MMSS_DP_AUDIO_COPYMANAGEMENT_1 (0x0000067C)
+#define MMSS_DP_AUDIO_COPYMANAGEMENT_2 (0x00000680)
+#define MMSS_DP_AUDIO_COPYMANAGEMENT_3 (0x00000684)
+#define MMSS_DP_AUDIO_COPYMANAGEMENT_4 (0x00000688)
+#define MMSS_DP_AUDIO_COPYMANAGEMENT_5 (0x0000068C)
+#define MMSS_DP_AUDIO_ISRC_0 (0x00000690)
+#define MMSS_DP_AUDIO_ISRC_1 (0x00000694)
+#define MMSS_DP_AUDIO_ISRC_2 (0x00000698)
+#define MMSS_DP_AUDIO_ISRC_3 (0x0000069C)
+#define MMSS_DP_AUDIO_ISRC_4 (0x000006A0)
+#define MMSS_DP_AUDIO_ISRC_5 (0x000006A4)
+#define MMSS_DP_AUDIO_INFOFRAME_0 (0x000006A8)
+#define MMSS_DP_AUDIO_INFOFRAME_1 (0x000006AC)
+#define MMSS_DP_AUDIO_INFOFRAME_2 (0x000006B0)
+
+#define MMSS_DP_GENERIC0_0 (0x00000700)
+#define MMSS_DP_GENERIC0_1 (0x00000704)
+#define MMSS_DP_GENERIC0_2 (0x00000708)
+#define MMSS_DP_GENERIC0_3 (0x0000070C)
+#define MMSS_DP_GENERIC0_4 (0x00000710)
+#define MMSS_DP_GENERIC0_5 (0x00000714)
+#define MMSS_DP_GENERIC0_6 (0x00000718)
+#define MMSS_DP_GENERIC0_7 (0x0000071C)
+#define MMSS_DP_GENERIC0_8 (0x00000720)
+#define MMSS_DP_GENERIC0_9 (0x00000724)
+#define MMSS_DP_GENERIC1_0 (0x00000728)
+#define MMSS_DP_GENERIC1_1 (0x0000072C)
+#define MMSS_DP_GENERIC1_2 (0x00000730)
+#define MMSS_DP_GENERIC1_3 (0x00000734)
+#define MMSS_DP_GENERIC1_4 (0x00000738)
+#define MMSS_DP_GENERIC1_5 (0x0000073C)
+#define MMSS_DP_GENERIC1_6 (0x00000740)
+#define MMSS_DP_GENERIC1_7 (0x00000744)
+#define MMSS_DP_GENERIC1_8 (0x00000748)
+#define MMSS_DP_GENERIC1_9 (0x0000074C)
+
+#define MMSS_DP_TIMING_ENGINE_EN (0x00000A10)
+#define MMSS_DP_ASYNC_FIFO_CONFIG (0x00000A88)
+
+/*DP PHY Register offsets */
+#define DP_PHY_REVISION_ID0 (0x00000000)
+#define DP_PHY_REVISION_ID1 (0x00000004)
+#define DP_PHY_REVISION_ID2 (0x00000008)
+#define DP_PHY_REVISION_ID3 (0x0000000C)
+
+#define DP_PHY_CFG (0x00000010)
+#define DP_PHY_PD_CTL (0x00000018)
+#define DP_PHY_MODE (0x0000001C)
+
+#define DP_PHY_AUX_CFG0 (0x00000020)
+#define DP_PHY_AUX_CFG1 (0x00000024)
+#define DP_PHY_AUX_CFG2 (0x00000028)
+#define DP_PHY_AUX_CFG3 (0x0000002C)
+#define DP_PHY_AUX_CFG4 (0x00000030)
+#define DP_PHY_AUX_CFG5 (0x00000034)
+#define DP_PHY_AUX_CFG6 (0x00000038)
+#define DP_PHY_AUX_CFG7 (0x0000003C)
+#define DP_PHY_AUX_CFG8 (0x00000040)
+#define DP_PHY_AUX_CFG9 (0x00000044)
+#define DP_PHY_AUX_INTERRUPT_MASK (0x00000048)
+#define DP_PHY_AUX_INTERRUPT_CLEAR (0x0000004C)
+
+#define DP_PHY_SPARE0 (0x00AC)
+
+#define TXn_TX_EMP_POST1_LVL (0x000C)
+#define TXn_TX_DRV_LVL (0x001C)
+
+#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN (0x004)
+
+/* DP MMSS_CC registers */
+#define MMSS_DP_LINK_CMD_RCGR (0x0138)
+#define MMSS_DP_LINK_CFG_RCGR (0x013C)
+#define MMSS_DP_PIXEL_M (0x0174)
+#define MMSS_DP_PIXEL_N (0x0178)
+
+/* DP HDCP 1.3 registers */
+#define DP_HDCP_CTRL (0x0A0)
+#define DP_HDCP_STATUS (0x0A4)
+#define DP_HDCP_SW_UPPER_AKSV (0x298)
+#define DP_HDCP_SW_LOWER_AKSV (0x29C)
+#define DP_HDCP_ENTROPY_CTRL0 (0x750)
+#define DP_HDCP_ENTROPY_CTRL1 (0x75C)
+#define DP_HDCP_SHA_STATUS (0x0C8)
+#define DP_HDCP_RCVPORT_DATA2_0 (0x0B0)
+#define DP_HDCP_RCVPORT_DATA3 (0x2A4)
+#define DP_HDCP_RCVPORT_DATA4 (0x2A8)
+#define DP_HDCP_RCVPORT_DATA5 (0x0C0)
+#define DP_HDCP_RCVPORT_DATA6 (0x0C4)
+
+#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_CTRL (0x024)
+#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_DATA (0x028)
+#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA0 (0x004)
+#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA1 (0x008)
+#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA7 (0x00C)
+#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA8 (0x010)
+#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA9 (0x014)
+#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA10 (0x018)
+#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA11 (0x01C)
+#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA12 (0x020)
+
+#endif /* _DP_REG_H_ */
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
index c0c6698..195584f 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
@@ -141,6 +141,31 @@
}
}
+int dsi_display_set_power(struct drm_connector *connector,
+ int power_mode, void *disp)
+{
+ struct dsi_display *display = disp;
+ int rc = 0;
+
+ if (!display || !display->panel) {
+ pr_err("invalid display/panel\n");
+ return -EINVAL;
+ }
+
+ switch (power_mode) {
+ case SDE_MODE_DPMS_LP1:
+ rc = dsi_panel_set_lp1(display->panel);
+ break;
+ case SDE_MODE_DPMS_LP2:
+ rc = dsi_panel_set_lp2(display->panel);
+ break;
+ default:
+ rc = dsi_panel_set_nolp(display->panel);
+ break;
+ }
+ return rc;
+}
+
static ssize_t debugfs_dump_info_read(struct file *file,
char __user *user_buf,
size_t user_len,
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
index 359e04f3..0ded247 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
@@ -477,6 +477,22 @@
*/
int dsi_display_soft_reset(void *display);
+/**
+ * dsi_display_set_power - update power/dpms setting
+ * @connector: Pointer to drm connector structure
+ * @power_mode: One of the following,
+ * SDE_MODE_DPMS_ON
+ * SDE_MODE_DPMS_LP1
+ * SDE_MODE_DPMS_LP2
+ * SDE_MODE_DPMS_STANDBY
+ * SDE_MODE_DPMS_SUSPEND
+ * SDE_MODE_DPMS_OFF
+ * @display: Pointer to private display structure
+ * Returns: Zero on success
+ */
+int dsi_display_set_power(struct drm_connector *connector,
+ int power_mode, void *display);
+
/*
* dsi_display_pre_kickoff - program kickoff-time features
* @display: Pointer to private display structure
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
index 8bc82f5..81da506 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
@@ -1333,6 +1333,9 @@
"qcom,video-to-cmd-mode-switch-commands",
"qcom,video-to-cmd-mode-post-switch-commands",
"qcom,mdss-dsi-panel-status-command",
+ "qcom,mdss-dsi-lp1-command",
+ "qcom,mdss-dsi-lp2-command",
+ "qcom,mdss-dsi-nolp-command",
"PPS not parsed from DTSI, generated dynamically",
"ROI not parsed from DTSI, generated dynamically",
};
@@ -1352,6 +1355,9 @@
"qcom,video-to-cmd-mode-switch-commands-state",
"qcom,video-to-cmd-mode-post-switch-commands-state",
"qcom,mdss-dsi-panel-status-command-state",
+ "qcom,mdss-dsi-lp1-command-state",
+ "qcom,mdss-dsi-lp2-command-state",
+ "qcom,mdss-dsi-nolp-command-state",
"PPS not parsed from DTSI, generated dynamically",
"ROI not parsed from DTSI, generated dynamically",
};
@@ -2745,6 +2751,60 @@
return rc;
}
+int dsi_panel_set_lp1(struct dsi_panel *panel)
+{
+ int rc = 0;
+
+ if (!panel) {
+ pr_err("invalid params\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&panel->panel_lock);
+ rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_LP1);
+ if (rc)
+ pr_err("[%s] failed to send DSI_CMD_SET_LP1 cmd, rc=%d\n",
+ panel->name, rc);
+ mutex_unlock(&panel->panel_lock);
+ return rc;
+}
+
+int dsi_panel_set_lp2(struct dsi_panel *panel)
+{
+ int rc = 0;
+
+ if (!panel) {
+ pr_err("invalid params\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&panel->panel_lock);
+ rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_LP2);
+ if (rc)
+ pr_err("[%s] failed to send DSI_CMD_SET_LP2 cmd, rc=%d\n",
+ panel->name, rc);
+ mutex_unlock(&panel->panel_lock);
+ return rc;
+}
+
+int dsi_panel_set_nolp(struct dsi_panel *panel)
+{
+ int rc = 0;
+
+ if (!panel) {
+ pr_err("invalid params\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&panel->panel_lock);
+ rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_NOLP);
+ if (rc)
+ pr_err("[%s] failed to send DSI_CMD_SET_NOLP cmd, rc=%d\n",
+ panel->name, rc);
+ mutex_unlock(&panel->panel_lock);
+ return rc;
+}
+
int dsi_panel_prepare(struct dsi_panel *panel)
{
int rc = 0;
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
index 5380049..ef9bb0c 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
@@ -55,6 +55,9 @@
DSI_CMD_SET_VID_TO_CMD_SWITCH,
DSI_CMD_SET_POST_VID_TO_CMD_SWITCH,
DSI_CMD_SET_PANEL_STATUS,
+ DSI_CMD_SET_LP1,
+ DSI_CMD_SET_LP2,
+ DSI_CMD_SET_NOLP,
DSI_CMD_SET_PPS,
DSI_CMD_SET_ROI,
DSI_CMD_SET_MAX
@@ -230,6 +233,12 @@
int dsi_panel_pre_prepare(struct dsi_panel *panel);
+int dsi_panel_set_lp1(struct dsi_panel *panel);
+
+int dsi_panel_set_lp2(struct dsi_panel *panel);
+
+int dsi_panel_set_nolp(struct dsi_panel *panel);
+
int dsi_panel_prepare(struct dsi_panel *panel);
int dsi_panel_enable(struct dsi_panel *panel);
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.h b/drivers/gpu/drm/msm/sde/sde_connector.h
index 1598968..1b594cd 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.h
+++ b/drivers/gpu/drm/msm/sde/sde_connector.h
@@ -381,6 +381,20 @@
}
/**
+ * sde_connector_get_lp - helper accessor to retrieve LP state
+ * @connector: pointer to drm connector
+ * Returns: value of the CONNECTOR_PROP_LP property or 0
+ */
+static inline uint64_t sde_connector_get_lp(
+ struct drm_connector *connector)
+{
+ if (!connector || !connector->state)
+ return 0;
+ return sde_connector_get_property(connector->state,
+ CONNECTOR_PROP_LP);
+}
+
+/**
* sde_connector_init - create drm connector object for a given display
* @dev: Pointer to drm device struct
* @encoder: Pointer to associated encoder
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index ef220b9..d41ddec 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -72,6 +72,7 @@
#define MISR_BUFF_SIZE 256
#define IDLE_TIMEOUT 64
+#define IDLE_SHORT_TIMEOUT 1
/**
* enum sde_enc_rc_events - events for resource control state machine
@@ -1346,6 +1347,7 @@
{
bool schedule_off = false;
bool autorefresh_enabled = false;
+ unsigned int lp, idle_timeout;
struct sde_encoder_virt *sde_enc;
struct msm_drm_private *priv;
struct msm_drm_thread *disp_thread;
@@ -1435,13 +1437,26 @@
sde_enc->cur_master->ops.is_autorefresh_enabled(
sde_enc->cur_master);
+ /* set idle timeout based on master connector's lp value */
+ if (sde_enc->cur_master)
+ lp = sde_connector_get_lp(
+ sde_enc->cur_master->connector);
+ else
+ lp = SDE_MODE_DPMS_ON;
+
+ if (lp == SDE_MODE_DPMS_LP2)
+ idle_timeout = IDLE_SHORT_TIMEOUT;
+ else
+ idle_timeout = IDLE_TIMEOUT;
+
if (!autorefresh_enabled)
kthread_queue_delayed_work(
&disp_thread->worker,
&sde_enc->delayed_off_work,
- msecs_to_jiffies(IDLE_TIMEOUT));
+ msecs_to_jiffies(idle_timeout));
SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
- SDE_EVTLOG_FUNC_CASE2);
+ autorefresh_enabled,
+ idle_timeout, SDE_EVTLOG_FUNC_CASE2);
SDE_DEBUG_ENC(sde_enc, "sw_event:%d, work scheduled\n",
sw_event);
break;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
index a502008..d8cd75a 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
@@ -771,6 +771,16 @@
SDE_REG_WRITE(&ctx->hw, QSEED3_OP_MODE + idx, op_mode);
}
+static u32 _sde_hw_sspp_get_scaler3_ver(struct sde_hw_pipe *ctx)
+{
+ u32 idx;
+
+ if (!ctx || _sspp_subblk_offset(ctx, SDE_SSPP_SCALER_QSEED3, &idx))
+ return 0;
+
+ return SDE_REG_READ(&ctx->hw, QSEED3_HW_VERSION + idx);
+}
+
/**
* sde_hw_sspp_setup_rects()
*/
@@ -1170,8 +1180,10 @@
if (sde_hw_sspp_multirect_enabled(c->cap))
c->ops.setup_multirect = sde_hw_sspp_setup_multirect;
- if (test_bit(SDE_SSPP_SCALER_QSEED3, &features))
+ if (test_bit(SDE_SSPP_SCALER_QSEED3, &features)) {
c->ops.setup_scaler = _sde_hw_sspp_setup_scaler3;
+ c->ops.get_scaler_ver = _sde_hw_sspp_get_scaler3_ver;
+ }
if (test_bit(SDE_SSPP_HSIC, &features)) {
/* TODO: add version based assignment here as inline or macro */
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_sspp.h b/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
index 8d14715..c19eb5c 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
@@ -575,6 +575,12 @@
void *scaler_cfg);
/**
+ * get_scaler_ver - get scaler h/w version
+ * @ctx: Pointer to pipe context
+ */
+ u32 (*get_scaler_ver)(struct sde_hw_pipe *ctx);
+
+ /**
* setup_sys_cache - setup system cache configuration
* @ctx: Pointer to pipe context
* @cfg: Pointer to system cache configuration
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_vbif.c b/drivers/gpu/drm/msm/sde/sde_hw_vbif.c
index b5c273a..9e6a246 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_vbif.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_vbif.c
@@ -22,7 +22,7 @@
#define VBIF_QOS_REMAP_01 0x0024
#define VBIF_QOS_REMAP_10 0x0028
#define VBIF_QOS_REMAP_11 0x002C
-#define VBIF_WRITE_GATHTER_EN 0x00AC
+#define VBIF_WRITE_GATHER_EN 0x00AC
#define VBIF_IN_RD_LIM_CONF0 0x00B0
#define VBIF_IN_RD_LIM_CONF1 0x00B4
#define VBIF_IN_RD_LIM_CONF2 0x00B8
@@ -167,6 +167,21 @@
SDE_REG_WRITE(c, VBIF_XINL_QOS_LVL_REMAP_000 + reg_high, reg_val_lvl);
}
+static void sde_hw_set_write_gather_en(struct sde_hw_vbif *vbif, u32 xin_id)
+{
+ struct sde_hw_blk_reg_map *c;
+ u32 reg_val;
+
+ if (!vbif || xin_id >= MAX_XIN_COUNT)
+ return;
+
+ c = &vbif->hw;
+
+ reg_val = SDE_REG_READ(c, VBIF_WRITE_GATHER_EN);
+ reg_val |= BIT(xin_id);
+ SDE_REG_WRITE(c, VBIF_WRITE_GATHER_EN, reg_val);
+}
+
static void _setup_vbif_ops(struct sde_hw_vbif_ops *ops,
unsigned long cap)
{
@@ -177,6 +192,7 @@
if (test_bit(SDE_VBIF_QOS_REMAP, &cap))
ops->set_qos_remap = sde_hw_set_qos_remap;
ops->set_mem_type = sde_hw_set_mem_type;
+ ops->set_write_gather_en = sde_hw_set_write_gather_en;
}
static const struct sde_vbif_cfg *_top_offset(enum sde_vbif vbif,
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_vbif.h b/drivers/gpu/drm/msm/sde/sde_hw_vbif.h
index 80a9e5a..81cb9d6 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_vbif.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_vbif.h
@@ -80,6 +80,13 @@
*/
void (*set_mem_type)(struct sde_hw_vbif *vbif,
u32 xin_id, u32 value);
+
+ /**
+ * set_write_gather_en - set write_gather enable
+ * @vbif: vbif context driver
+ * @xin_id: client interface identifier
+ */
+ void (*set_write_gather_en)(struct sde_hw_vbif *vbif, u32 xin_id);
};
struct sde_hw_vbif {
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index 94bbc99..8747288 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -641,6 +641,7 @@
.soft_reset = dsi_display_soft_reset,
.pre_kickoff = dsi_conn_pre_kickoff,
.clk_ctrl = dsi_display_clk_ctrl,
+ .set_power = dsi_display_set_power,
.get_topology = dsi_conn_get_topology,
.get_dst_format = dsi_display_get_dst_format
};
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index 5a014bc7..1affa9c 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -3806,6 +3806,10 @@
sde_kms_info_stop(info);
}
+ if (psde->pipe_hw && psde->pipe_hw->ops.get_scaler_ver)
+ sde_kms_info_add_keyint(info, "scaler_step_ver",
+ psde->pipe_hw->ops.get_scaler_ver(psde->pipe_hw));
+
sde_kms_info_add_keyint(info, "max_linewidth",
psde->pipe_sblk->maxlinewidth);
sde_kms_info_add_keyint(info, "max_upscale",
diff --git a/drivers/gpu/drm/msm/sde/sde_vbif.c b/drivers/gpu/drm/msm/sde/sde_vbif.c
index 847572b..d31f828 100644
--- a/drivers/gpu/drm/msm/sde/sde_vbif.c
+++ b/drivers/gpu/drm/msm/sde/sde_vbif.c
@@ -184,6 +184,10 @@
!vbif->ops.set_halt_ctrl)
return;
+ /* set write_gather_en for all write clients */
+ if (vbif->ops.set_write_gather_en && !params->rd)
+ vbif->ops.set_write_gather_en(vbif, params->xin_id);
+
ot_lim = _sde_vbif_get_ot_limit(vbif, params) & 0xFF;
if (ot_lim == 0)
diff --git a/drivers/gpu/drm/msm/sde_edid_parser.c b/drivers/gpu/drm/msm/sde_edid_parser.c
index 3c03b92..3d6c2ea 100644
--- a/drivers/gpu/drm/msm/sde_edid_parser.c
+++ b/drivers/gpu/drm/msm/sde_edid_parser.c
@@ -571,6 +571,11 @@
struct sde_edid_ctrl *edid_ctrl = (struct sde_edid_ctrl *)(input);
struct edid *edid = edid_ctrl->edid;
+ if (!edid) {
+ SDE_ERROR("invalid edid input\n");
+ return 0;
+ }
+
if ((edid->revision < 3) || !(edid->input & DRM_EDID_INPUT_DIGITAL))
return 0;
diff --git a/drivers/gpu/drm/msm/sde_hdcp.h b/drivers/gpu/drm/msm/sde_hdcp.h
new file mode 100644
index 0000000..05d290b
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde_hdcp.h
@@ -0,0 +1,75 @@
+/* Copyright (c) 2012, 2014-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __SDE_HDCP_H__
+#define __SDE_HDCP_H__
+
+#include <soc/qcom/scm.h>
+
+#include <linux/types.h>
+#include <linux/bitops.h>
+#include <linux/debugfs.h>
+#include <linux/of_device.h>
+#include <linux/i2c.h>
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_edid.h>
+#include "sde_kms.h"
+
+enum sde_hdcp_client_id {
+ HDCP_CLIENT_HDMI,
+ HDCP_CLIENT_DP,
+};
+
+enum sde_hdcp_states {
+ HDCP_STATE_INACTIVE,
+ HDCP_STATE_AUTHENTICATING,
+ HDCP_STATE_AUTHENTICATED,
+ HDCP_STATE_AUTH_FAIL,
+ HDCP_STATE_AUTH_ENC_NONE,
+ HDCP_STATE_AUTH_ENC_1X,
+ HDCP_STATE_AUTH_ENC_2P2
+};
+
+struct sde_hdcp_init_data {
+ struct dss_io_data *core_io;
+ struct dss_io_data *qfprom_io;
+ struct dss_io_data *hdcp_io;
+ struct drm_dp_aux *drm_aux;
+ struct mutex *mutex;
+ struct workqueue_struct *workq;
+ void *cb_data;
+ void (*notify_status)(void *cb_data, enum sde_hdcp_states status);
+ u8 sink_rx_status;
+ unsigned char *revision;
+ u32 phy_addr;
+ bool sec_access;
+ enum sde_hdcp_client_id client_id;
+};
+
+struct sde_hdcp_ops {
+ int (*isr)(void *ptr);
+ int (*cp_irq)(void *ptr);
+ int (*reauthenticate)(void *input);
+ int (*authenticate)(void *hdcp_ctrl);
+ bool (*feature_supported)(void *input);
+ void (*off)(void *hdcp_ctrl);
+};
+
+void *sde_hdcp_1x_init(struct sde_hdcp_init_data *init_data);
+void sde_hdcp_1x_deinit(void *input);
+struct sde_hdcp_ops *sde_hdcp_1x_start(void *input);
+void *sde_dp_hdcp2p2_init(struct sde_hdcp_init_data *init_data);
+void sde_dp_hdcp2p2_deinit(void *input);
+const char *sde_hdcp_state_name(enum sde_hdcp_states hdcp_state);
+struct sde_hdcp_ops *sde_dp_hdcp2p2_start(void *input);
+#endif /* __SDE_HDCP_H__ */
diff --git a/drivers/gpu/drm/msm/sde_hdcp_1x.c b/drivers/gpu/drm/msm/sde_hdcp_1x.c
new file mode 100644
index 0000000..7951c23
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde_hdcp_1x.c
@@ -0,0 +1,1579 @@
+/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "[sde-hdcp1x] %s: " fmt, __func__
+
+#include <linux/io.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/stat.h>
+#include <linux/iopoll.h>
+#include <linux/hdcp_qseecom.h>
+#include <drm/drm_dp_helper.h>
+#include "sde_hdcp.h"
+#include "hdmi.xml.h"
+#include "video/msm_hdmi_hdcp_mgr.h"
+#include "dp/dp_reg.h"
+
+#define SDE_HDCP_STATE_NAME (sde_hdcp_state_name(hdcp->hdcp_state))
+
+/* QFPROM Registers for HDMI/HDCP */
+#define QFPROM_RAW_FEAT_CONFIG_ROW0_LSB (0x000000F8)
+#define QFPROM_RAW_FEAT_CONFIG_ROW0_MSB (0x000000FC)
+#define QFPROM_RAW_VERSION_4 (0x000000A8)
+#define SEC_CTRL_HW_VERSION (0x00006000)
+#define HDCP_KSV_LSB (0x000060D8)
+#define HDCP_KSV_MSB (0x000060DC)
+#define HDCP_KSV_VERSION_4_OFFSET (0x00000014)
+
+/* SEC_CTRL version that supports HDCP SEL */
+#define HDCP_SEL_MIN_SEC_VERSION (0x50010000)
+
+/* HDCP Keys state based on HDMI_HDCP_LINK0_STATUS:KEYS_STATE */
+#define HDCP_KEYS_STATE_NO_KEYS 0
+#define HDCP_KEYS_STATE_NOT_CHECKED 1
+#define HDCP_KEYS_STATE_CHECKING 2
+#define HDCP_KEYS_STATE_VALID 3
+#define HDCP_KEYS_STATE_AKSV_NOT_VALID 4
+#define HDCP_KEYS_STATE_CHKSUM_MISMATCH 5
+#define HDCP_KEYS_STATE_PROD_AKSV 6
+#define HDCP_KEYS_STATE_RESERVED 7
+
+#define TZ_HDCP_CMD_ID 0x00004401
+
+#define HDCP_INT_CLR (isr->auth_success_ack | isr->auth_fail_ack | \
+ isr->auth_fail_info_ack | isr->tx_req_ack | \
+ isr->encryption_ready_ack | \
+ isr->encryption_not_ready_ack | isr->tx_req_done_ack)
+
+#define HDCP_INT_EN (isr->auth_success_mask | isr->auth_fail_mask | \
+ isr->encryption_ready_mask | \
+ isr->encryption_not_ready_mask)
+
+#define HDCP_POLL_SLEEP_US (20 * 1000)
+#define HDCP_POLL_TIMEOUT_US (HDCP_POLL_SLEEP_US * 100)
+
+#define sde_hdcp_1x_state(x) (hdcp->hdcp_state == x)
+
+struct sde_hdcp_sink_addr {
+ char *name;
+ u32 addr;
+ u32 len;
+};
+
+struct sde_hdcp_1x_reg_data {
+ u32 reg_id;
+ struct sde_hdcp_sink_addr *sink;
+};
+
+struct sde_hdcp_sink_addr_map {
+ /* addresses to read from sink */
+ struct sde_hdcp_sink_addr bcaps;
+ struct sde_hdcp_sink_addr bksv;
+ struct sde_hdcp_sink_addr r0;
+ struct sde_hdcp_sink_addr bstatus;
+ struct sde_hdcp_sink_addr cp_irq_status;
+ struct sde_hdcp_sink_addr ksv_fifo;
+ struct sde_hdcp_sink_addr v_h0;
+ struct sde_hdcp_sink_addr v_h1;
+ struct sde_hdcp_sink_addr v_h2;
+ struct sde_hdcp_sink_addr v_h3;
+ struct sde_hdcp_sink_addr v_h4;
+
+ /* addresses to write to sink */
+ struct sde_hdcp_sink_addr an;
+ struct sde_hdcp_sink_addr aksv;
+ struct sde_hdcp_sink_addr ainfo;
+};
+
+struct sde_hdcp_int_set {
+ /* interrupt register */
+ u32 int_reg;
+
+ /* interrupt enable/disable masks */
+ u32 auth_success_mask;
+ u32 auth_fail_mask;
+ u32 encryption_ready_mask;
+ u32 encryption_not_ready_mask;
+ u32 tx_req_mask;
+ u32 tx_req_done_mask;
+
+ /* interrupt acknowledgment */
+ u32 auth_success_ack;
+ u32 auth_fail_ack;
+ u32 auth_fail_info_ack;
+ u32 encryption_ready_ack;
+ u32 encryption_not_ready_ack;
+ u32 tx_req_ack;
+ u32 tx_req_done_ack;
+
+ /* interrupt status */
+ u32 auth_success_int;
+ u32 auth_fail_int;
+ u32 encryption_ready;
+ u32 encryption_not_ready;
+ u32 tx_req_int;
+ u32 tx_req_done_int;
+};
+
+struct sde_hdcp_reg_set {
+ u32 status;
+ u32 keys_offset;
+ u32 r0_offset;
+ u32 v_offset;
+ u32 ctrl;
+ u32 aksv_lsb;
+ u32 aksv_msb;
+ u32 entropy_ctrl0;
+ u32 entropy_ctrl1;
+ u32 sec_sha_ctrl;
+ u32 sec_sha_data;
+ u32 sha_status;
+
+ u32 data2_0;
+ u32 data3;
+ u32 data4;
+ u32 data5;
+ u32 data6;
+
+ u32 sec_data0;
+ u32 sec_data1;
+ u32 sec_data7;
+ u32 sec_data8;
+ u32 sec_data9;
+ u32 sec_data10;
+ u32 sec_data11;
+ u32 sec_data12;
+
+ u32 reset;
+ u32 reset_bit;
+
+ u32 repeater;
+};
+
+#define HDCP_REG_SET_CLIENT_HDMI \
+ {0}
+
+#define HDCP_REG_SET_CLIENT_DP \
+{DP_HDCP_STATUS, 16, 14, 13, DP_HDCP_CTRL, \
+ DP_HDCP_SW_LOWER_AKSV, DP_HDCP_SW_UPPER_AKSV, \
+ DP_HDCP_ENTROPY_CTRL0, DP_HDCP_ENTROPY_CTRL1, \
+ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_CTRL, \
+ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_DATA, \
+ DP_HDCP_SHA_STATUS, DP_HDCP_RCVPORT_DATA2_0, \
+ DP_HDCP_RCVPORT_DATA3, DP_HDCP_RCVPORT_DATA4, \
+ DP_HDCP_RCVPORT_DATA5, DP_HDCP_RCVPORT_DATA6, \
+ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA0, \
+ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA1, \
+ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA7, \
+ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA8, \
+ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA9, \
+ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA10, \
+ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA11, \
+ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA12, \
+ DP_SW_RESET, BIT(1), BIT(1)}
+
+#define HDCP_HDMI_SINK_ADDR_MAP \
+ {{"bcaps", 0x40, 1}, {"bksv", 0x00, 5}, {"r0'", 0x08, 2}, \
+ {"bstatus", 0x41, 2}, {"??", 0x0, 0}, {"ksv-fifo", 0x43, 0}, \
+ {"v_h0", 0x20, 4}, {"v_h1", 0x24, 4}, {"v_h2", 0x28, 4}, \
+ {"v_h3", 0x2c, 4}, {"v_h4", 0x30, 4}, {"an", 0x18, 8}, \
+ {"aksv", 0x10, 5}, {"ainfo", 0x00, 0},}
+
+#define HDCP_DP_SINK_ADDR_MAP \
+ {{"bcaps", 0x68028, 1}, {"bksv", 0x68000, 5}, {"r0'", 0x68005, 2}, \
+ {"binfo", 0x6802A, 2}, {"cp_irq_status", 0x68029, 1}, \
+ {"ksv-fifo", 0x6802C, 0}, {"v_h0", 0x68014, 4}, {"v_h1", 0x68018, 4}, \
+ {"v_h2", 0x6801C, 4}, {"v_h3", 0x68020, 4}, {"v_h4", 0x68024, 4}, \
+ {"an", 0x6800C, 8}, {"aksv", 0x68007, 5}, {"ainfo", 0x6803B, 1} }
+
+#define HDCP_HDMI_INT_SET \
+ {0}
+
+#define HDCP_DP_INT_SET \
+ {DP_INTR_STATUS2, \
+ BIT(17), BIT(20), BIT(24), BIT(27), 0, 0, \
+ BIT(16), BIT(19), BIT(21), BIT(23), BIT(26), 0, 0, \
+ BIT(15), BIT(18), BIT(22), BIT(25), 0, 0}
+
+struct sde_hdcp_1x {
+ u8 bcaps;
+ u32 tp_msgid;
+ u32 an_0, an_1, aksv_0, aksv_1;
+ bool sink_r0_ready;
+ bool reauth;
+ bool ksv_ready;
+ enum sde_hdcp_states hdcp_state;
+ struct HDCP_V2V1_MSG_TOPOLOGY cached_tp;
+ struct HDCP_V2V1_MSG_TOPOLOGY current_tp;
+ struct delayed_work hdcp_auth_work;
+ struct completion r0_checked;
+ struct completion sink_r0_available;
+ struct sde_hdcp_init_data init_data;
+ struct sde_hdcp_ops *ops;
+ struct sde_hdcp_reg_set reg_set;
+ struct sde_hdcp_int_set int_set;
+ struct sde_hdcp_sink_addr_map sink_addr;
+ struct workqueue_struct *workq;
+};
+
+const char *sde_hdcp_state_name(enum sde_hdcp_states hdcp_state)
+{
+ switch (hdcp_state) {
+ case HDCP_STATE_INACTIVE: return "HDCP_STATE_INACTIVE";
+ case HDCP_STATE_AUTHENTICATING: return "HDCP_STATE_AUTHENTICATING";
+ case HDCP_STATE_AUTHENTICATED: return "HDCP_STATE_AUTHENTICATED";
+ case HDCP_STATE_AUTH_FAIL: return "HDCP_STATE_AUTH_FAIL";
+ default: return "???";
+ }
+}
+
+static int sde_hdcp_1x_count_one(u8 *array, u8 len)
+{
+ int i, j, count = 0;
+
+ for (i = 0; i < len; i++)
+ for (j = 0; j < 8; j++)
+ count += (((array[i] >> j) & 0x1) ? 1 : 0);
+ return count;
+}
+
+static int sde_hdcp_1x_load_keys(void *input)
+{
+ int rc = 0;
+ bool use_sw_keys = false;
+ u32 reg_val;
+ u32 ksv_lsb_addr, ksv_msb_addr;
+ u32 aksv_lsb, aksv_msb;
+ u8 aksv[5];
+ struct dss_io_data *io;
+ struct dss_io_data *qfprom_io;
+ struct sde_hdcp_1x *hdcp = input;
+ struct sde_hdcp_reg_set *reg_set;
+
+ if (!hdcp || !hdcp->init_data.core_io ||
+ !hdcp->init_data.qfprom_io) {
+ pr_err("invalid input\n");
+ rc = -EINVAL;
+ goto end;
+ }
+
+ if (!sde_hdcp_1x_state(HDCP_STATE_INACTIVE) &&
+ !sde_hdcp_1x_state(HDCP_STATE_AUTH_FAIL)) {
+ pr_err("%s: invalid state. returning\n",
+ SDE_HDCP_STATE_NAME);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ io = hdcp->init_data.core_io;
+ qfprom_io = hdcp->init_data.qfprom_io;
+ reg_set = &hdcp->reg_set;
+
+ /* On compatible hardware, use SW keys */
+ reg_val = DSS_REG_R(qfprom_io, SEC_CTRL_HW_VERSION);
+ if (reg_val >= HDCP_SEL_MIN_SEC_VERSION) {
+ reg_val = DSS_REG_R(qfprom_io,
+ QFPROM_RAW_FEAT_CONFIG_ROW0_MSB +
+ QFPROM_RAW_VERSION_4);
+
+ if (!(reg_val & BIT(23)))
+ use_sw_keys = true;
+ }
+
+ if (use_sw_keys) {
+ if (hdcp1_set_keys(&aksv_msb, &aksv_lsb)) {
+ pr_err("setting hdcp SW keys failed\n");
+ rc = -EINVAL;
+ goto end;
+ }
+ } else {
+ /* Fetch aksv from QFPROM, this info should be public. */
+ ksv_lsb_addr = HDCP_KSV_LSB;
+ ksv_msb_addr = HDCP_KSV_MSB;
+
+ if (hdcp->init_data.sec_access) {
+ ksv_lsb_addr += HDCP_KSV_VERSION_4_OFFSET;
+ ksv_msb_addr += HDCP_KSV_VERSION_4_OFFSET;
+ }
+
+ aksv_lsb = DSS_REG_R(qfprom_io, ksv_lsb_addr);
+ aksv_msb = DSS_REG_R(qfprom_io, ksv_msb_addr);
+ }
+
+ pr_debug("%s: AKSV=%02x%08x\n", SDE_HDCP_STATE_NAME,
+ aksv_msb, aksv_lsb);
+
+ aksv[0] = aksv_lsb & 0xFF;
+ aksv[1] = (aksv_lsb >> 8) & 0xFF;
+ aksv[2] = (aksv_lsb >> 16) & 0xFF;
+ aksv[3] = (aksv_lsb >> 24) & 0xFF;
+ aksv[4] = aksv_msb & 0xFF;
+
+ /* check there are 20 ones in AKSV */
+ if (sde_hdcp_1x_count_one(aksv, 5) != 20) {
+ pr_err("AKSV bit count failed\n");
+ rc = -EINVAL;
+ goto end;
+ }
+
+ DSS_REG_W(io, reg_set->aksv_lsb, aksv_lsb);
+ DSS_REG_W(io, reg_set->aksv_msb, aksv_msb);
+
+ /* Setup seed values for random number An */
+ DSS_REG_W(io, reg_set->entropy_ctrl0, 0xB1FFB0FF);
+ DSS_REG_W(io, reg_set->entropy_ctrl1, 0xF00DFACE);
+
+ /* make sure hw is programmed */
+ wmb();
+
+ /* enable hdcp engine */
+ DSS_REG_W(io, reg_set->ctrl, 0x1);
+
+ hdcp->hdcp_state = HDCP_STATE_AUTHENTICATING;
+end:
+ return rc;
+}
+
+static int sde_hdcp_1x_read(struct sde_hdcp_1x *hdcp,
+ struct sde_hdcp_sink_addr *sink,
+ u8 *buf, bool realign)
+{
+ int const max_size = 15;
+ int rc = 0, read_size = 0, bytes_read = 0;
+
+ if (hdcp->init_data.client_id == HDCP_CLIENT_DP) {
+ int size = sink->len, offset = sink->addr;
+
+ do {
+ read_size = min(size, max_size);
+
+ bytes_read = drm_dp_dpcd_read(hdcp->init_data.drm_aux,
+ offset, buf, read_size);
+ if (bytes_read != read_size) {
+ pr_err("fail: offset(0x%x), size(0x%x), rc(0x%x)\n",
+ offset, read_size, bytes_read);
+ break;
+ }
+
+ buf += read_size;
+ offset += read_size;
+ size -= read_size;
+ } while (size > 0);
+ }
+
+ return rc;
+}
+
+static int sde_hdcp_1x_write(struct sde_hdcp_1x *hdcp,
+ struct sde_hdcp_sink_addr *sink, u8 *buf)
+{
+ int const max_size = 16;
+ int rc = 0, write_size = 0, bytes_written = 0;
+
+ if (hdcp->init_data.client_id == HDCP_CLIENT_DP) {
+ int size = sink->len, offset = sink->addr;
+
+ do {
+ write_size = min(size, max_size);
+
+ bytes_written =
+ drm_dp_dpcd_write(hdcp->init_data.drm_aux,
+ offset, buf, write_size);
+ if (bytes_written != write_size) {
+ pr_err("fail: offset(0x%x), size(0x%x), rc(0x%x)\n",
+ offset, write_size, bytes_written);
+ break;
+ }
+
+ buf += write_size;
+ offset += write_size;
+ size -= write_size;
+ } while (size > 0);
+ }
+
+ return rc;
+}
+
+static void sde_hdcp_1x_enable_interrupts(struct sde_hdcp_1x *hdcp)
+{
+ u32 intr_reg;
+ struct dss_io_data *io;
+ struct sde_hdcp_int_set *isr;
+
+ io = hdcp->init_data.core_io;
+ isr = &hdcp->int_set;
+
+ intr_reg = DSS_REG_R(io, isr->int_reg);
+
+ intr_reg |= HDCP_INT_CLR | HDCP_INT_EN;
+
+ DSS_REG_W(io, isr->int_reg, intr_reg);
+}
+
+static int sde_hdcp_1x_read_bcaps(struct sde_hdcp_1x *hdcp)
+{
+ int rc;
+ struct sde_hdcp_reg_set *reg_set = &hdcp->reg_set;
+ struct dss_io_data *hdcp_io = hdcp->init_data.hdcp_io;
+
+ if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("invalid state\n");
+ return -EINVAL;
+ }
+
+ rc = sde_hdcp_1x_read(hdcp, &hdcp->sink_addr.bcaps,
+ &hdcp->bcaps, false);
+ if (rc) {
+ pr_err("error reading bcaps\n");
+ goto error;
+ }
+
+ pr_debug("bcaps read: 0x%x\n", hdcp->bcaps);
+
+ hdcp->current_tp.ds_type = hdcp->bcaps & reg_set->repeater ?
+ DS_REPEATER : DS_RECEIVER;
+
+ pr_debug("ds: %s\n", hdcp->current_tp.ds_type == DS_REPEATER ?
+ "repeater" : "receiver");
+
+ /* Write BCAPS to the hardware */
+ DSS_REG_W(hdcp_io, reg_set->sec_data12, hdcp->bcaps);
+error:
+ return rc;
+}
+
+static int sde_hdcp_1x_wait_for_hw_ready(struct sde_hdcp_1x *hdcp)
+{
+ int rc;
+ u32 link0_status;
+ struct sde_hdcp_reg_set *reg_set = &hdcp->reg_set;
+ struct dss_io_data *io = hdcp->init_data.core_io;
+
+ if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("invalid state\n");
+ return -EINVAL;
+ }
+
+ /* Wait for HDCP keys to be checked and validated */
+ rc = readl_poll_timeout(io->base + reg_set->status, link0_status,
+ ((link0_status >> reg_set->keys_offset) & 0x7)
+ == HDCP_KEYS_STATE_VALID ||
+ !sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING),
+ HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US);
+ if (rc) {
+ pr_err("key not ready\n");
+ goto error;
+ }
+
+ /*
+ * 1.1_Features turned off by default.
+ * No need to write AInfo since 1.1_Features is disabled.
+ */
+ DSS_REG_W(io, reg_set->data4, 0);
+
+ /* Wait for An0 and An1 bit to be ready */
+ rc = readl_poll_timeout(io->base + reg_set->status, link0_status,
+ (link0_status & (BIT(8) | BIT(9))) ||
+ !sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING),
+ HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US);
+ if (rc) {
+ pr_err("An not ready\n");
+ goto error;
+ }
+
+ /* As per hardware recommendations, wait before reading An */
+ msleep(20);
+error:
+ if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING))
+ rc = -EINVAL;
+
+ return rc;
+}
+
+static int sde_hdcp_1x_send_an_aksv_to_sink(struct sde_hdcp_1x *hdcp)
+{
+ int rc;
+ u8 an[8], aksv[5];
+
+ if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("invalid state\n");
+ return -EINVAL;
+ }
+
+ an[0] = hdcp->an_0 & 0xFF;
+ an[1] = (hdcp->an_0 >> 8) & 0xFF;
+ an[2] = (hdcp->an_0 >> 16) & 0xFF;
+ an[3] = (hdcp->an_0 >> 24) & 0xFF;
+ an[4] = hdcp->an_1 & 0xFF;
+ an[5] = (hdcp->an_1 >> 8) & 0xFF;
+ an[6] = (hdcp->an_1 >> 16) & 0xFF;
+ an[7] = (hdcp->an_1 >> 24) & 0xFF;
+
+ pr_debug("an read: 0x%2x%2x%2x%2x%2x%2x%2x%2x\n",
+ an[7], an[6], an[5], an[4], an[3], an[2], an[1], an[0]);
+
+ rc = sde_hdcp_1x_write(hdcp, &hdcp->sink_addr.an, an);
+ if (rc) {
+ pr_err("error writing an to sink\n");
+ goto error;
+ }
+
+ /* Copy An and AKSV to byte arrays for transmission */
+ aksv[0] = hdcp->aksv_0 & 0xFF;
+ aksv[1] = (hdcp->aksv_0 >> 8) & 0xFF;
+ aksv[2] = (hdcp->aksv_0 >> 16) & 0xFF;
+ aksv[3] = (hdcp->aksv_0 >> 24) & 0xFF;
+ aksv[4] = hdcp->aksv_1 & 0xFF;
+
+ pr_debug("aksv read: 0x%2x%2x%2x%2x%2x\n",
+ aksv[4], aksv[3], aksv[2], aksv[1], aksv[0]);
+
+ rc = sde_hdcp_1x_write(hdcp, &hdcp->sink_addr.aksv, aksv);
+ if (rc) {
+ pr_err("error writing aksv to sink\n");
+ goto error;
+ }
+error:
+ return rc;
+}
+
+static int sde_hdcp_1x_read_an_aksv_from_hw(struct sde_hdcp_1x *hdcp)
+{
+ struct dss_io_data *io = hdcp->init_data.core_io;
+ struct sde_hdcp_reg_set *reg_set = &hdcp->reg_set;
+
+ if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("invalid state\n");
+ return -EINVAL;
+ }
+
+ hdcp->an_0 = DSS_REG_R(io, reg_set->data5);
+ if (hdcp->init_data.client_id == HDCP_CLIENT_DP) {
+ udelay(1);
+ hdcp->an_0 = DSS_REG_R(io, reg_set->data5);
+ }
+
+ hdcp->an_1 = DSS_REG_R(io, reg_set->data6);
+ if (hdcp->init_data.client_id == HDCP_CLIENT_DP) {
+ udelay(1);
+ hdcp->an_1 = DSS_REG_R(io, reg_set->data6);
+ }
+
+ /* Read AKSV */
+ hdcp->aksv_0 = DSS_REG_R(io, reg_set->data3);
+ hdcp->aksv_1 = DSS_REG_R(io, reg_set->data4);
+
+ return 0;
+}
+
+static int sde_hdcp_1x_get_bksv_from_sink(struct sde_hdcp_1x *hdcp)
+{
+ int rc;
+ u8 *bksv = hdcp->current_tp.bksv;
+ u32 link0_bksv_0, link0_bksv_1;
+ struct sde_hdcp_reg_set *reg_set = &hdcp->reg_set;
+ struct dss_io_data *hdcp_io = hdcp->init_data.hdcp_io;
+
+ rc = sde_hdcp_1x_read(hdcp, &hdcp->sink_addr.bksv, bksv, false);
+ if (rc) {
+ pr_err("error reading bksv from sink\n");
+ goto error;
+ }
+
+ pr_debug("bksv read: 0x%2x%2x%2x%2x%2x\n",
+ bksv[4], bksv[3], bksv[2], bksv[1], bksv[0]);
+
+ /* check there are 20 ones in BKSV */
+ if (sde_hdcp_1x_count_one(bksv, 5) != 20) {
+ pr_err("%s: BKSV doesn't have 20 1's and 20 0's\n",
+ SDE_HDCP_STATE_NAME);
+ rc = -EINVAL;
+ goto error;
+ }
+
+ link0_bksv_0 = bksv[3];
+ link0_bksv_0 = (link0_bksv_0 << 8) | bksv[2];
+ link0_bksv_0 = (link0_bksv_0 << 8) | bksv[1];
+ link0_bksv_0 = (link0_bksv_0 << 8) | bksv[0];
+ link0_bksv_1 = bksv[4];
+
+ DSS_REG_W(hdcp_io, reg_set->sec_data0, link0_bksv_0);
+ DSS_REG_W(hdcp_io, reg_set->sec_data1, link0_bksv_1);
+error:
+ return rc;
+}
+
+static void sde_hdcp_1x_enable_sink_irq_hpd(struct sde_hdcp_1x *hdcp)
+{
+ u8 const required_major = 1, required_minor = 2;
+ u8 sink_major = 0, sink_minor = 0;
+ u8 enable_hpd_irq = 0x1;
+ int rc;
+ unsigned char revision = *hdcp->init_data.revision;
+
+ sink_major = (revision >> 4) & 0x0f;
+ sink_minor = revision & 0x0f;
+ pr_debug("revision: %d.%d\n", sink_major, sink_minor);
+
+ if ((sink_minor < required_minor) || (sink_major < required_major) ||
+ (hdcp->current_tp.ds_type != DS_REPEATER)) {
+ pr_debug("sink irq hpd not enabled\n");
+ return;
+ }
+
+ rc = sde_hdcp_1x_write(hdcp, &hdcp->sink_addr.ainfo, &enable_hpd_irq);
+ if (rc)
+ pr_debug("error writing ainfo to sink\n");
+}
+
+static int sde_hdcp_1x_verify_r0(struct sde_hdcp_1x *hdcp)
+{
+ int rc, r0_retry = 3;
+ u8 buf[2];
+ u32 link0_status, timeout_count;
+ u32 const r0_read_delay_us = 1;
+ u32 const r0_read_timeout_us = r0_read_delay_us * 10;
+ struct sde_hdcp_reg_set *reg_set = &hdcp->reg_set;
+ struct dss_io_data *io = hdcp->init_data.core_io;
+
+ if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("invalid state\n");
+ return -EINVAL;
+ }
+
+ /* Wait for HDCP R0 computation to be completed */
+ rc = readl_poll_timeout(io->base + reg_set->status, link0_status,
+ (link0_status & BIT(reg_set->r0_offset)) ||
+ !sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING),
+ HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US);
+ if (rc) {
+ pr_err("R0 not ready\n");
+ goto error;
+ }
+
+ /*
+ * HDCP Compliace Test case 1A-01:
+ * Wait here at least 100ms before reading R0'
+ */
+ if (hdcp->init_data.client_id == HDCP_CLIENT_HDMI) {
+ msleep(100);
+ } else {
+ if (!hdcp->sink_r0_ready) {
+ reinit_completion(&hdcp->sink_r0_available);
+ timeout_count = wait_for_completion_timeout(
+ &hdcp->sink_r0_available, HZ / 2);
+
+ if (hdcp->reauth) {
+ pr_err("sink R0 not ready\n");
+ rc = -EINVAL;
+ goto error;
+ }
+ }
+ }
+
+ do {
+ memset(buf, 0, sizeof(buf));
+
+ rc = sde_hdcp_1x_read(hdcp, &hdcp->sink_addr.r0,
+ buf, false);
+ if (rc) {
+ pr_err("error reading R0' from sink\n");
+ goto error;
+ }
+
+ pr_debug("sink R0'read: %2x%2x\n", buf[1], buf[0]);
+
+ DSS_REG_W(io, reg_set->data2_0, (((u32)buf[1]) << 8) | buf[0]);
+
+ rc = readl_poll_timeout(io->base + reg_set->status,
+ link0_status, (link0_status & BIT(12)) ||
+ !sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING),
+ r0_read_delay_us, r0_read_timeout_us);
+ } while (rc && --r0_retry);
+error:
+ if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING))
+ rc = -EINVAL;
+
+ return rc;
+}
+
+static int sde_hdcp_1x_authentication_part1(struct sde_hdcp_1x *hdcp)
+{
+ int rc;
+
+ if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("invalid state\n");
+ return -EINVAL;
+ }
+
+ sde_hdcp_1x_enable_interrupts(hdcp);
+
+ rc = sde_hdcp_1x_read_bcaps(hdcp);
+ if (rc)
+ goto error;
+
+ rc = sde_hdcp_1x_wait_for_hw_ready(hdcp);
+ if (rc)
+ goto error;
+
+ rc = sde_hdcp_1x_read_an_aksv_from_hw(hdcp);
+ if (rc)
+ goto error;
+
+ rc = sde_hdcp_1x_get_bksv_from_sink(hdcp);
+ if (rc)
+ goto error;
+
+ rc = sde_hdcp_1x_send_an_aksv_to_sink(hdcp);
+ if (rc)
+ goto error;
+
+ sde_hdcp_1x_enable_sink_irq_hpd(hdcp);
+
+ rc = sde_hdcp_1x_verify_r0(hdcp);
+ if (rc)
+ goto error;
+
+ pr_info("SUCCESSFUL\n");
+
+ return 0;
+error:
+ pr_err("%s: FAILED\n", SDE_HDCP_STATE_NAME);
+
+ return rc;
+}
+
+static int sde_hdcp_1x_transfer_v_h(struct sde_hdcp_1x *hdcp)
+{
+ int rc = 0;
+ struct dss_io_data *io = hdcp->init_data.hdcp_io;
+ struct sde_hdcp_reg_set *reg_set = &hdcp->reg_set;
+ struct sde_hdcp_1x_reg_data reg_data[] = {
+ {reg_set->sec_data7, &hdcp->sink_addr.v_h0},
+ {reg_set->sec_data8, &hdcp->sink_addr.v_h1},
+ {reg_set->sec_data9, &hdcp->sink_addr.v_h2},
+ {reg_set->sec_data10, &hdcp->sink_addr.v_h3},
+ {reg_set->sec_data11, &hdcp->sink_addr.v_h4},
+ };
+ struct sde_hdcp_sink_addr sink = {"V", reg_data->sink->addr};
+ u32 size = ARRAY_SIZE(reg_data);
+ u8 buf[0xFF] = {0};
+ u32 i = 0, len = 0;
+
+ if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("invalid state\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < size; i++) {
+ struct sde_hdcp_1x_reg_data *rd = reg_data + i;
+
+ len += rd->sink->len;
+ }
+
+ sink.len = len;
+
+ rc = sde_hdcp_1x_read(hdcp, &sink, buf, false);
+ if (rc) {
+ pr_err("error reading %s\n", sink.name);
+ goto end;
+ }
+
+ for (i = 0; i < size; i++) {
+ struct sde_hdcp_1x_reg_data *rd = reg_data + i;
+ u32 reg_data;
+
+ memcpy(®_data, buf + (sizeof(u32) * i), sizeof(u32));
+ DSS_REG_W(io, rd->reg_id, reg_data);
+ }
+end:
+ return rc;
+}
+
+static int sde_hdcp_1x_validate_downstream(struct sde_hdcp_1x *hdcp)
+{
+ int rc;
+ u8 buf[2] = {0, 0};
+ u8 device_count, depth;
+ u8 max_cascade_exceeded, max_devs_exceeded;
+ u16 bstatus;
+ struct sde_hdcp_reg_set *reg_set = &hdcp->reg_set;
+
+ if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("invalid state\n");
+ return -EINVAL;
+ }
+
+ rc = sde_hdcp_1x_read(hdcp, &hdcp->sink_addr.bstatus,
+ buf, false);
+ if (rc) {
+ pr_err("error reading bstatus\n");
+ goto end;
+ }
+
+ bstatus = buf[1];
+ bstatus = (bstatus << 8) | buf[0];
+
+ device_count = bstatus & 0x7F;
+
+ pr_debug("device count %d\n", device_count);
+
+ /* Cascaded repeater depth */
+ depth = (bstatus >> 8) & 0x7;
+ pr_debug("depth %d\n", depth);
+
+ /*
+ * HDCP Compliance 1B-05:
+ * Check if no. of devices connected to repeater
+ * exceed max_devices_connected from bit 7 of Bstatus.
+ */
+ max_devs_exceeded = (bstatus & BIT(7)) >> 7;
+ if (max_devs_exceeded == 0x01) {
+ pr_err("no. of devs connected exceed max allowed\n");
+ rc = -EINVAL;
+ goto end;
+ }
+
+ /*
+ * HDCP Compliance 1B-06:
+ * Check if no. of cascade connected to repeater
+ * exceed max_cascade_connected from bit 11 of Bstatus.
+ */
+ max_cascade_exceeded = (bstatus & BIT(11)) >> 11;
+ if (max_cascade_exceeded == 0x01) {
+ pr_err("no. of cascade connections exceed max allowed\n");
+ rc = -EINVAL;
+ goto end;
+ }
+
+ /* Update topology information */
+ hdcp->current_tp.dev_count = device_count;
+ hdcp->current_tp.max_cascade_exceeded = max_cascade_exceeded;
+ hdcp->current_tp.max_dev_exceeded = max_devs_exceeded;
+ hdcp->current_tp.depth = depth;
+
+ DSS_REG_W(hdcp->init_data.hdcp_io,
+ reg_set->sec_data12, hdcp->bcaps | (bstatus << 8));
+end:
+ return rc;
+}
+
+static int sde_hdcp_1x_read_ksv_fifo(struct sde_hdcp_1x *hdcp)
+{
+ u32 ksv_read_retry = 20, ksv_bytes, rc = 0;
+ u8 *ksv_fifo = hdcp->current_tp.ksv_list;
+
+ if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("invalid state\n");
+ return -EINVAL;
+ }
+
+ memset(ksv_fifo, 0, sizeof(hdcp->current_tp.ksv_list));
+
+ /* each KSV is 5 bytes long */
+ ksv_bytes = 5 * hdcp->current_tp.dev_count;
+ hdcp->sink_addr.ksv_fifo.len = ksv_bytes;
+
+ while (ksv_bytes && --ksv_read_retry) {
+ rc = sde_hdcp_1x_read(hdcp, &hdcp->sink_addr.ksv_fifo,
+ ksv_fifo, true);
+ if (rc)
+ pr_err("could not read ksv fifo (%d)\n",
+ ksv_read_retry);
+ else
+ break;
+ }
+
+ if (rc)
+ pr_err("error reading ksv_fifo\n");
+
+ return rc;
+}
+
+static int sde_hdcp_1x_write_ksv_fifo(struct sde_hdcp_1x *hdcp)
+{
+ int i, rc = 0;
+ u8 *ksv_fifo = hdcp->current_tp.ksv_list;
+ u32 ksv_bytes = hdcp->sink_addr.ksv_fifo.len;
+ struct dss_io_data *io = hdcp->init_data.core_io;
+ struct dss_io_data *sec_io = hdcp->init_data.hdcp_io;
+ struct sde_hdcp_reg_set *reg_set = &hdcp->reg_set;
+ u32 sha_status = 0, status;
+
+ if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("invalid state\n");
+ return -EINVAL;
+ }
+
+ /* reset SHA Controller */
+ DSS_REG_W(sec_io, reg_set->sec_sha_ctrl, 0x1);
+ DSS_REG_W(sec_io, reg_set->sec_sha_ctrl, 0x0);
+
+ for (i = 0; i < ksv_bytes - 1; i++) {
+ /* Write KSV byte and do not set DONE bit[0] */
+ DSS_REG_W_ND(sec_io, reg_set->sec_sha_data, ksv_fifo[i] << 16);
+
+ /*
+ * Once 64 bytes have been written, we need to poll for
+ * HDCP_SHA_BLOCK_DONE before writing any further
+ */
+ if (i && !((i + 1) % 64)) {
+ rc = readl_poll_timeout(io->base + reg_set->sha_status,
+ sha_status, (sha_status & BIT(0)) ||
+ !sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING),
+ HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US);
+ if (rc) {
+ pr_err("block not done\n");
+ goto error;
+ }
+ }
+ }
+
+ /* Write l to DONE bit[0] */
+ DSS_REG_W_ND(sec_io, reg_set->sec_sha_data,
+ (ksv_fifo[ksv_bytes - 1] << 16) | 0x1);
+
+ /* Now wait for HDCP_SHA_COMP_DONE */
+ rc = readl_poll_timeout(io->base + reg_set->sha_status, sha_status,
+ (sha_status & BIT(4)) ||
+ !sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING),
+ HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US);
+ if (rc) {
+ pr_err("V computation not done\n");
+ goto error;
+ }
+
+ /* Wait for V_MATCHES */
+ rc = readl_poll_timeout(io->base + reg_set->status, status,
+ (status & BIT(reg_set->v_offset)) ||
+ !sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING),
+ HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US);
+ if (rc) {
+ pr_err("V mismatch\n");
+ rc = -EINVAL;
+ }
+error:
+ if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING))
+ rc = -EINVAL;
+
+ return rc;
+}
+
+static int sde_hdcp_1x_wait_for_ksv_ready(struct sde_hdcp_1x *hdcp)
+{
+ int rc, timeout;
+
+ if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("invalid state\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Wait until READY bit is set in BCAPS, as per HDCP specifications
+ * maximum permitted time to check for READY bit is five seconds.
+ */
+ rc = sde_hdcp_1x_read(hdcp, &hdcp->sink_addr.bcaps,
+ &hdcp->bcaps, false);
+ if (rc) {
+ pr_err("error reading bcaps\n");
+ goto error;
+ }
+
+ if (hdcp->init_data.client_id == HDCP_CLIENT_HDMI) {
+ timeout = 50;
+
+ while (!(hdcp->bcaps & BIT(5)) && --timeout) {
+ rc = sde_hdcp_1x_read(hdcp,
+ &hdcp->sink_addr.bcaps,
+ &hdcp->bcaps, false);
+ if (rc ||
+ !sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("error reading bcaps\n");
+ goto error;
+ }
+ msleep(100);
+ }
+ } else {
+ u8 cp_buf = 0;
+ struct sde_hdcp_sink_addr *sink =
+ &hdcp->sink_addr.cp_irq_status;
+
+ timeout = jiffies_to_msecs(jiffies);
+
+ while (1) {
+ rc = sde_hdcp_1x_read(hdcp, sink, &cp_buf, false);
+ if (rc)
+ goto error;
+
+ if (cp_buf & BIT(0))
+ break;
+
+ /* max timeout of 5 sec as per hdcp 1.x spec */
+ if (abs(timeout - jiffies_to_msecs(jiffies)) > 5000) {
+ timeout = 0;
+ break;
+ }
+
+ if (hdcp->ksv_ready || hdcp->reauth ||
+ !sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING))
+ break;
+
+ /* re-read after a minimum delay */
+ msleep(20);
+ }
+ }
+
+ if (!timeout || hdcp->reauth ||
+ !sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("DS KSV not ready\n");
+ rc = -EINVAL;
+ } else {
+ hdcp->ksv_ready = true;
+ }
+error:
+ return rc;
+}
+
+static int sde_hdcp_1x_authentication_part2(struct sde_hdcp_1x *hdcp)
+{
+ int rc;
+ int v_retry = 3;
+
+ rc = sde_hdcp_1x_validate_downstream(hdcp);
+ if (rc)
+ goto error;
+
+ rc = sde_hdcp_1x_read_ksv_fifo(hdcp);
+ if (rc)
+ goto error;
+
+ do {
+ rc = sde_hdcp_1x_transfer_v_h(hdcp);
+ if (rc)
+ goto error;
+
+ /* do not proceed further if no device connected */
+ if (!hdcp->current_tp.dev_count)
+ goto error;
+
+ rc = sde_hdcp_1x_write_ksv_fifo(hdcp);
+ } while (--v_retry && rc);
+error:
+ if (rc) {
+ pr_err("%s: FAILED\n", SDE_HDCP_STATE_NAME);
+ } else {
+ hdcp->hdcp_state = HDCP_STATE_AUTHENTICATED;
+
+ pr_info("SUCCESSFUL\n");
+ }
+
+ return rc;
+}
+
+static void sde_hdcp_1x_cache_topology(struct sde_hdcp_1x *hdcp)
+{
+ if (!hdcp || !hdcp->init_data.core_io) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ memcpy((void *)&hdcp->cached_tp,
+ (void *) &hdcp->current_tp,
+ sizeof(hdcp->cached_tp));
+ hdcp1_cache_repeater_topology((void *)&hdcp->cached_tp);
+}
+
+static void sde_hdcp_1x_notify_topology(void)
+{
+ hdcp1_notify_topology();
+}
+
+static void sde_hdcp_1x_update_auth_status(struct sde_hdcp_1x *hdcp)
+{
+ if (sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATED)) {
+ sde_hdcp_1x_cache_topology(hdcp);
+ sde_hdcp_1x_notify_topology();
+ }
+
+ if (hdcp->init_data.notify_status &&
+ !sde_hdcp_1x_state(HDCP_STATE_INACTIVE)) {
+ hdcp->init_data.notify_status(
+ hdcp->init_data.cb_data,
+ hdcp->hdcp_state);
+ }
+}
+
+static void sde_hdcp_1x_auth_work(struct work_struct *work)
+{
+ int rc;
+ struct delayed_work *dw = to_delayed_work(work);
+ struct sde_hdcp_1x *hdcp = container_of(dw,
+ struct sde_hdcp_1x, hdcp_auth_work);
+ struct dss_io_data *io;
+
+ if (!hdcp) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("invalid state\n");
+ return;
+ }
+
+ hdcp->sink_r0_ready = false;
+ hdcp->reauth = false;
+ hdcp->ksv_ready = false;
+
+ io = hdcp->init_data.core_io;
+ /* Enabling Software DDC for HDMI and REF timer for DP */
+ if (hdcp->init_data.client_id == HDCP_CLIENT_HDMI)
+ DSS_REG_W_ND(io, REG_HDMI_DDC_ARBITRATION, DSS_REG_R(io,
+ REG_HDMI_DDC_ARBITRATION) & ~(BIT(4)));
+ else if (hdcp->init_data.client_id == HDCP_CLIENT_DP) {
+ DSS_REG_W(io, DP_DP_HPD_REFTIMER, 0x10013);
+ }
+
+ /*
+ * program hw to enable encryption as soon as
+ * authentication is successful.
+ */
+ hdcp1_set_enc(true);
+
+ rc = sde_hdcp_1x_authentication_part1(hdcp);
+ if (rc)
+ goto end;
+
+ if (hdcp->current_tp.ds_type == DS_REPEATER) {
+ rc = sde_hdcp_1x_wait_for_ksv_ready(hdcp);
+ if (rc)
+ goto end;
+ } else {
+ hdcp->hdcp_state = HDCP_STATE_AUTHENTICATED;
+ goto end;
+ }
+
+ hdcp->ksv_ready = false;
+
+ rc = sde_hdcp_1x_authentication_part2(hdcp);
+ if (rc)
+ goto end;
+
+ /*
+ * Disabling software DDC before going into part3 to make sure
+ * there is no Arbitration between software and hardware for DDC
+ */
+ if (hdcp->init_data.client_id == HDCP_CLIENT_HDMI)
+ DSS_REG_W_ND(io, REG_HDMI_DDC_ARBITRATION, DSS_REG_R(io,
+ REG_HDMI_DDC_ARBITRATION) | (BIT(4)));
+end:
+ if (rc && !sde_hdcp_1x_state(HDCP_STATE_INACTIVE))
+ hdcp->hdcp_state = HDCP_STATE_AUTH_FAIL;
+
+ sde_hdcp_1x_update_auth_status(hdcp);
+}
+
+static int sde_hdcp_1x_authenticate(void *input)
+{
+ struct sde_hdcp_1x *hdcp = (struct sde_hdcp_1x *)input;
+
+ if (!hdcp) {
+ pr_err("invalid input\n");
+ return -EINVAL;
+ }
+
+ flush_delayed_work(&hdcp->hdcp_auth_work);
+
+ if (!sde_hdcp_1x_state(HDCP_STATE_INACTIVE)) {
+ pr_err("invalid state\n");
+ return -EINVAL;
+ }
+
+ if (!sde_hdcp_1x_load_keys(input)) {
+
+ queue_delayed_work(hdcp->workq,
+ &hdcp->hdcp_auth_work, HZ/2);
+ } else {
+ hdcp->hdcp_state = HDCP_STATE_AUTH_FAIL;
+ sde_hdcp_1x_update_auth_status(hdcp);
+ }
+
+ return 0;
+} /* hdcp_1x_authenticate */
+
+static int sde_hdcp_1x_reauthenticate(void *input)
+{
+ struct sde_hdcp_1x *hdcp = (struct sde_hdcp_1x *)input;
+ struct dss_io_data *io;
+ struct sde_hdcp_reg_set *reg_set;
+ struct sde_hdcp_int_set *isr;
+ u32 ret = 0, reg;
+
+ if (!hdcp || !hdcp->init_data.core_io) {
+ pr_err("invalid input\n");
+ return -EINVAL;
+ }
+
+ io = hdcp->init_data.core_io;
+ reg_set = &hdcp->reg_set;
+ isr = &hdcp->int_set;
+
+ if (!sde_hdcp_1x_state(HDCP_STATE_AUTH_FAIL)) {
+ pr_err("invalid state\n");
+ return -EINVAL;
+ }
+
+ /* Disable HDCP interrupts */
+ DSS_REG_W(io, isr->int_reg, DSS_REG_R(io, isr->int_reg) & ~HDCP_INT_EN);
+
+ reg = DSS_REG_R(io, reg_set->reset);
+ DSS_REG_W(io, reg_set->reset, reg | reg_set->reset_bit);
+
+ /* Disable encryption and disable the HDCP block */
+ DSS_REG_W(io, reg_set->ctrl, 0);
+
+ DSS_REG_W(io, reg_set->reset, reg & ~reg_set->reset_bit);
+
+ hdcp->hdcp_state = HDCP_STATE_INACTIVE;
+ sde_hdcp_1x_authenticate(hdcp);
+
+ return ret;
+} /* hdcp_1x_reauthenticate */
+
+static void sde_hdcp_1x_off(void *input)
+{
+ struct sde_hdcp_1x *hdcp = (struct sde_hdcp_1x *)input;
+ struct dss_io_data *io;
+ struct sde_hdcp_reg_set *reg_set;
+ struct sde_hdcp_int_set *isr;
+ int rc = 0;
+ u32 reg;
+
+ if (!hdcp || !hdcp->init_data.core_io) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ io = hdcp->init_data.core_io;
+ reg_set = &hdcp->reg_set;
+ isr = &hdcp->int_set;
+
+ if (sde_hdcp_1x_state(HDCP_STATE_INACTIVE)) {
+ pr_err("invalid state\n");
+ return;
+ }
+
+ /*
+ * Disable HDCP interrupts.
+ * Also, need to set the state to inactive here so that any ongoing
+ * reauth works will know that the HDCP session has been turned off.
+ */
+ mutex_lock(hdcp->init_data.mutex);
+ DSS_REG_W(io, isr->int_reg,
+ DSS_REG_R(io, isr->int_reg) & ~HDCP_INT_EN);
+ hdcp->hdcp_state = HDCP_STATE_INACTIVE;
+ mutex_unlock(hdcp->init_data.mutex);
+
+ /* complete any wait pending */
+ complete_all(&hdcp->sink_r0_available);
+ complete_all(&hdcp->r0_checked);
+ /*
+ * Cancel any pending auth/reauth attempts.
+ * If one is ongoing, this will wait for it to finish.
+ * No more reauthentiaction attempts will be scheduled since we
+ * set the currect state to inactive.
+ */
+ rc = cancel_delayed_work_sync(&hdcp->hdcp_auth_work);
+ if (rc)
+ pr_debug("%s: Deleted hdcp auth work\n",
+ SDE_HDCP_STATE_NAME);
+
+ hdcp1_set_enc(false);
+
+ reg = DSS_REG_R(io, reg_set->reset);
+ DSS_REG_W(io, reg_set->reset, reg | reg_set->reset_bit);
+
+ /* Disable encryption and disable the HDCP block */
+ DSS_REG_W(io, reg_set->ctrl, 0);
+
+ DSS_REG_W(io, reg_set->reset, reg & ~reg_set->reset_bit);
+
+ hdcp->sink_r0_ready = false;
+
+ pr_debug("%s: HDCP: Off\n", SDE_HDCP_STATE_NAME);
+} /* hdcp_1x_off */
+
+static int sde_hdcp_1x_isr(void *input)
+{
+ struct sde_hdcp_1x *hdcp = (struct sde_hdcp_1x *)input;
+ int rc = 0;
+ struct dss_io_data *io;
+ u32 hdcp_int_val;
+ struct sde_hdcp_reg_set *reg_set;
+ struct sde_hdcp_int_set *isr;
+
+ if (!hdcp || !hdcp->init_data.core_io) {
+ pr_err("invalid input\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ io = hdcp->init_data.core_io;
+ reg_set = &hdcp->reg_set;
+ isr = &hdcp->int_set;
+
+ hdcp_int_val = DSS_REG_R(io, isr->int_reg);
+
+ /* Ignore HDCP interrupts if HDCP is disabled */
+ if (sde_hdcp_1x_state(HDCP_STATE_INACTIVE)) {
+ DSS_REG_W(io, isr->int_reg, hdcp_int_val | HDCP_INT_CLR);
+ return 0;
+ }
+
+ if (hdcp_int_val & isr->auth_success_int) {
+ /* AUTH_SUCCESS_INT */
+ DSS_REG_W(io, isr->int_reg,
+ (hdcp_int_val | isr->auth_success_ack));
+ pr_debug("%s: AUTH SUCCESS\n", SDE_HDCP_STATE_NAME);
+
+ if (sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING))
+ complete_all(&hdcp->r0_checked);
+ }
+
+ if (hdcp_int_val & isr->auth_fail_int) {
+ /* AUTH_FAIL_INT */
+ u32 link_status = DSS_REG_R(io, reg_set->status);
+
+ DSS_REG_W(io, isr->int_reg,
+ (hdcp_int_val | isr->auth_fail_ack));
+
+ pr_debug("%s: AUTH FAIL, LINK0_STATUS=0x%08x\n",
+ SDE_HDCP_STATE_NAME, link_status);
+
+ if (sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATED)) {
+ hdcp->hdcp_state = HDCP_STATE_AUTH_FAIL;
+ sde_hdcp_1x_update_auth_status(hdcp);
+ } else if (sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ complete_all(&hdcp->r0_checked);
+ }
+
+ /* Clear AUTH_FAIL_INFO as well */
+ DSS_REG_W(io, isr->int_reg,
+ (hdcp_int_val | isr->auth_fail_info_ack));
+ }
+
+ if (hdcp_int_val & isr->tx_req_int) {
+ /* DDC_XFER_REQ_INT */
+ DSS_REG_W(io, isr->int_reg,
+ (hdcp_int_val | isr->tx_req_ack));
+ pr_debug("%s: DDC_XFER_REQ_INT received\n",
+ SDE_HDCP_STATE_NAME);
+ }
+
+ if (hdcp_int_val & isr->tx_req_done_int) {
+ /* DDC_XFER_DONE_INT */
+ DSS_REG_W(io, isr->int_reg,
+ (hdcp_int_val | isr->tx_req_done_ack));
+ pr_debug("%s: DDC_XFER_DONE received\n",
+ SDE_HDCP_STATE_NAME);
+ }
+
+ if (hdcp_int_val & isr->encryption_ready) {
+ /* Encryption enabled */
+ DSS_REG_W(io, isr->int_reg,
+ (hdcp_int_val | isr->encryption_ready_ack));
+ pr_debug("%s: encryption ready received\n",
+ SDE_HDCP_STATE_NAME);
+ }
+
+ if (hdcp_int_val & isr->encryption_not_ready) {
+ /* Encryption enabled */
+ DSS_REG_W(io, isr->int_reg,
+ (hdcp_int_val | isr->encryption_not_ready_ack));
+ pr_debug("%s: encryption not ready received\n",
+ SDE_HDCP_STATE_NAME);
+ }
+
+error:
+ return rc;
+}
+
+void sde_hdcp_1x_deinit(void *input)
+{
+ struct sde_hdcp_1x *hdcp = (struct sde_hdcp_1x *)input;
+
+ if (!hdcp) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ if (hdcp->workq)
+ destroy_workqueue(hdcp->workq);
+
+ kfree(hdcp);
+} /* hdcp_1x_deinit */
+
+static void sde_hdcp_1x_update_client_reg_set(struct sde_hdcp_1x *hdcp)
+{
+ if (hdcp->init_data.client_id == HDCP_CLIENT_DP) {
+ struct sde_hdcp_reg_set reg_set = HDCP_REG_SET_CLIENT_DP;
+ struct sde_hdcp_sink_addr_map sink_addr = HDCP_DP_SINK_ADDR_MAP;
+ struct sde_hdcp_int_set isr = HDCP_DP_INT_SET;
+
+ hdcp->reg_set = reg_set;
+ hdcp->sink_addr = sink_addr;
+ hdcp->int_set = isr;
+ }
+}
+
+static bool sde_hdcp_1x_is_cp_irq_raised(struct sde_hdcp_1x *hdcp)
+{
+ int ret;
+ u8 buf = 0;
+ struct sde_hdcp_sink_addr sink = {"irq", 0x201, 1};
+
+ ret = sde_hdcp_1x_read(hdcp, &sink, &buf, false);
+ if (ret)
+ pr_err("error reading irq_vector\n");
+
+ return buf & BIT(2) ? true : false;
+}
+
+static void sde_hdcp_1x_clear_cp_irq(struct sde_hdcp_1x *hdcp)
+{
+ int ret;
+ u8 buf = BIT(2);
+ struct sde_hdcp_sink_addr sink = {"irq", 0x201, 1};
+
+ ret = sde_hdcp_1x_write(hdcp, &sink, &buf);
+ if (ret)
+ pr_err("error clearing irq_vector\n");
+}
+
+static int sde_hdcp_1x_cp_irq(void *input)
+{
+ struct sde_hdcp_1x *hdcp = (struct sde_hdcp_1x *)input;
+ u8 buf = 0;
+ int ret;
+
+ if (!hdcp) {
+ pr_err("invalid input\n");
+ goto irq_not_handled;
+ }
+
+ if (!sde_hdcp_1x_is_cp_irq_raised(hdcp)) {
+ pr_debug("cp_irq not raised\n");
+ goto irq_not_handled;
+ }
+
+ ret = sde_hdcp_1x_read(hdcp, &hdcp->sink_addr.cp_irq_status,
+ &buf, false);
+ if (ret) {
+ pr_err("error reading cp_irq_status\n");
+ goto irq_not_handled;
+ }
+
+ if ((buf & BIT(2)) || (buf & BIT(3))) {
+ pr_err("%s\n",
+ buf & BIT(2) ? "LINK_INTEGRITY_FAILURE" :
+ "REAUTHENTICATION_REQUEST");
+
+ hdcp->reauth = true;
+
+ if (!sde_hdcp_1x_state(HDCP_STATE_INACTIVE))
+ hdcp->hdcp_state = HDCP_STATE_AUTH_FAIL;
+
+ complete_all(&hdcp->sink_r0_available);
+ sde_hdcp_1x_update_auth_status(hdcp);
+ } else if (buf & BIT(1)) {
+ pr_debug("R0' AVAILABLE\n");
+ hdcp->sink_r0_ready = true;
+ complete_all(&hdcp->sink_r0_available);
+ } else if ((buf & BIT(0))) {
+ pr_debug("KSVs READY\n");
+
+ hdcp->ksv_ready = true;
+ } else {
+ pr_debug("spurious interrupt\n");
+ }
+
+ sde_hdcp_1x_clear_cp_irq(hdcp);
+ return 0;
+
+irq_not_handled:
+ return -EINVAL;
+}
+
+void *sde_hdcp_1x_init(struct sde_hdcp_init_data *init_data)
+{
+ struct sde_hdcp_1x *hdcp = NULL;
+ char name[20];
+ static struct sde_hdcp_ops ops = {
+ .isr = sde_hdcp_1x_isr,
+ .cp_irq = sde_hdcp_1x_cp_irq,
+ .reauthenticate = sde_hdcp_1x_reauthenticate,
+ .authenticate = sde_hdcp_1x_authenticate,
+ .off = sde_hdcp_1x_off
+ };
+
+ if (!init_data || !init_data->core_io || !init_data->qfprom_io ||
+ !init_data->mutex || !init_data->notify_status ||
+ !init_data->workq || !init_data->cb_data) {
+ pr_err("invalid input\n");
+ goto error;
+ }
+
+ if (init_data->sec_access && !init_data->hdcp_io) {
+ pr_err("hdcp_io required\n");
+ goto error;
+ }
+
+ hdcp = kzalloc(sizeof(*hdcp), GFP_KERNEL);
+ if (!hdcp)
+ goto error;
+
+ hdcp->init_data = *init_data;
+ hdcp->ops = &ops;
+
+ snprintf(name, sizeof(name), "hdcp_1x_%d",
+ hdcp->init_data.client_id);
+
+ hdcp->workq = create_workqueue(name);
+ if (!hdcp->workq) {
+ pr_err("Error creating workqueue\n");
+ kfree(hdcp);
+ goto error;
+ }
+
+ sde_hdcp_1x_update_client_reg_set(hdcp);
+
+ INIT_DELAYED_WORK(&hdcp->hdcp_auth_work, sde_hdcp_1x_auth_work);
+
+ hdcp->hdcp_state = HDCP_STATE_INACTIVE;
+ init_completion(&hdcp->r0_checked);
+ init_completion(&hdcp->sink_r0_available);
+
+ pr_debug("HDCP module initialized. HDCP_STATE=%s\n",
+ SDE_HDCP_STATE_NAME);
+
+ return (void *)hdcp;
+
+error:
+ return NULL;
+} /* hdcp_1x_init */
+
+struct sde_hdcp_ops *sde_hdcp_1x_start(void *input)
+{
+ return ((struct sde_hdcp_1x *)input)->ops;
+}
diff --git a/drivers/gpu/msm/a6xx_reg.h b/drivers/gpu/msm/a6xx_reg.h
index 32ebe0c..156e3b4 100644
--- a/drivers/gpu/msm/a6xx_reg.h
+++ b/drivers/gpu/msm/a6xx_reg.h
@@ -720,10 +720,25 @@
/* VBIF registers */
#define A6XX_VBIF_VERSION 0x3000
+#define A6XX_VBIF_CLKON 0x3001
+#define A6XX_VBIF_CLKON_FORCE_ON_TESTBUS_MASK 0x1
+#define A6XX_VBIF_CLKON_FORCE_ON_TESTBUS_SHIFT 0x1
#define A6XX_VBIF_GATE_OFF_WRREQ_EN 0x302A
#define A6XX_VBIF_XIN_HALT_CTRL0 0x3080
#define A6XX_VBIF_XIN_HALT_CTRL0_MASK 0xF
#define A6XX_VBIF_XIN_HALT_CTRL1 0x3081
+#define A6XX_VBIF_TEST_BUS_OUT_CTRL 0x3084
+#define A6XX_VBIF_TEST_BUS_OUT_CTRL_EN_MASK 0x1
+#define A6XX_VBIF_TEST_BUS_OUT_CTRL_EN_SHIFT 0x0
+#define A6XX_VBIF_TEST_BUS1_CTRL0 0x3085
+#define A6XX_VBIF_TEST_BUS1_CTRL1 0x3086
+#define A6XX_VBIF_TEST_BUS1_CTRL1_DATA_SEL_MASK 0xF
+#define A6XX_VBIF_TEST_BUS1_CTRL1_DATA_SEL_SHIFT 0x0
+#define A6XX_VBIF_TEST_BUS2_CTRL0 0x3087
+#define A6XX_VBIF_TEST_BUS2_CTRL1 0x3088
+#define A6XX_VBIF_TEST_BUS2_CTRL1_DATA_SEL_MASK 0x1FF
+#define A6XX_VBIF_TEST_BUS2_CTRL1_DATA_SEL_SHIFT 0x0
+#define A6XX_VBIF_TEST_BUS_OUT 0x308C
#define A6XX_VBIF_PERF_CNT_SEL0 0x30d0
#define A6XX_VBIF_PERF_CNT_SEL1 0x30d1
#define A6XX_VBIF_PERF_CNT_SEL2 0x30d2
@@ -801,6 +816,7 @@
#define A6XX_GMU_DCVS_PERF_SETTING 0x1CBFD
#define A6XX_GMU_DCVS_BW_SETTING 0x1CBFE
#define A6XX_GMU_DCVS_RETURN 0x1CBFF
+#define A6XX_GMU_SYS_BUS_CONFIG 0x1F40F
#define A6XX_GMU_CM3_SYSRESET 0x1F800
#define A6XX_GMU_CM3_BOOT_CONFIG 0x1F801
#define A6XX_GMU_CM3_FW_BUSY 0x1F81A
diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c
index c1d2407..fb07dbc 100644
--- a/drivers/gpu/msm/adreno_a6xx.c
+++ b/drivers/gpu/msm/adreno_a6xx.c
@@ -357,7 +357,6 @@
/* enable top level HWCG */
kgsl_regwrite(device, A6XX_RBBM_CLOCK_CNTL, on ? 0x8AA8AA02 : 0);
- kgsl_regwrite(device, A5XX_RBBM_ISDB_CNT, on ? 0x00000182 : 0x00000180);
}
/*
@@ -904,6 +903,9 @@
/* Configure registers for idle setting. The setting is cumulative */
+ /* Disable GMU WB/RB buffer */
+ kgsl_gmu_regwrite(device, A6XX_GMU_SYS_BUS_CONFIG, 0x1);
+
kgsl_gmu_regwrite(device,
A6XX_GMU_PWR_COL_INTER_FRAME_CTRL, 0x9C40400);
@@ -2184,6 +2186,14 @@
return uche_client[uche_client_id & A6XX_UCHE_CLIENT_PF_CLIENT_ID_MASK];
}
+static void a6xx_cp_callback(struct adreno_device *adreno_dev, int bit)
+{
+ struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+
+ a6xx_preemption_trigger(adreno_dev);
+ adreno_dispatcher_schedule(device);
+}
+
#define A6XX_INT_MASK \
((1 << A6XX_INT_CP_AHB_ERROR) | \
(1 << A6XX_INT_ATB_ASYNCFIFO_OVERFLOW) | \
@@ -2221,7 +2231,7 @@
ADRENO_IRQ_CALLBACK(NULL), /* 17 - CP_RB_DONE_TS */
ADRENO_IRQ_CALLBACK(NULL), /* 18 - CP_WT_DONE_TS */
ADRENO_IRQ_CALLBACK(NULL), /* 19 - UNUSED */
- ADRENO_IRQ_CALLBACK(adreno_cp_callback), /* 20 - CP_CACHE_FLUSH_TS */
+ ADRENO_IRQ_CALLBACK(a6xx_cp_callback), /* 20 - CP_CACHE_FLUSH_TS */
ADRENO_IRQ_CALLBACK(NULL), /* 21 - UNUSED */
ADRENO_IRQ_CALLBACK(a6xx_err_callback), /* 22 - RBBM_ATB_BUS_OVERFLOW */
/* 23 - MISC_HANG_DETECT */
diff --git a/drivers/gpu/msm/adreno_a6xx_snapshot.c b/drivers/gpu/msm/adreno_a6xx_snapshot.c
index 1f97888..70afc91 100644
--- a/drivers/gpu/msm/adreno_a6xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a6xx_snapshot.c
@@ -21,6 +21,9 @@
#include "kgsl_gmu.h"
#define A6XX_NUM_CTXTS 2
+#define A6XX_NUM_AXI_ARB_BLOCKS 2
+#define A6XX_NUM_XIN_AXI_BLOCKS 5
+#define A6XX_NUM_XIN_CORE_BLOCKS 4
static const unsigned int a6xx_gras_cluster[] = {
0x8000, 0x8006, 0x8010, 0x8092, 0x8094, 0x809D, 0x80A0, 0x80A6,
@@ -393,9 +396,12 @@
{ A6XX_DBGBUS_TPL1_3, 0x100, },
};
+static const struct adreno_debugbus_block a6xx_vbif_debugbus_blocks = {
+ A6XX_DBGBUS_VBIF, 0x100,
+};
+
static void __iomem *a6xx_cx_dbgc;
static const struct adreno_debugbus_block a6xx_cx_dbgc_debugbus_blocks[] = {
- { A6XX_DBGBUS_VBIF, 0x100, },
{ A6XX_DBGBUS_GMU_CX, 0x100, },
{ A6XX_DBGBUS_CX, 0x100, },
};
@@ -1076,7 +1082,7 @@
kgsl_regread(device, A6XX_DBGC_CFG_DBGBUS_TRACE_BUF1, val);
}
-/* a6xx_snapshot_cbgc_debugbus_block() - Capture debug data for a gpu block */
+/* a6xx_snapshot_dbgc_debugbus_block() - Capture debug data for a gpu block */
static size_t a6xx_snapshot_dbgc_debugbus_block(struct kgsl_device *device,
u8 *buf, size_t remain, void *priv)
{
@@ -1115,6 +1121,89 @@
return size;
}
+/* a6xx_snapshot_vbif_debugbus_block() - Capture debug data for VBIF block */
+static size_t a6xx_snapshot_vbif_debugbus_block(struct kgsl_device *device,
+ u8 *buf, size_t remain, void *priv)
+{
+ struct kgsl_snapshot_debugbus *header =
+ (struct kgsl_snapshot_debugbus *)buf;
+ struct adreno_debugbus_block *block = priv;
+ int i, j;
+ /*
+ * Total number of VBIF data words considering 3 sections:
+ * 2 arbiter blocks of 16 words
+ * 5 AXI XIN blocks of 18 dwords each
+ * 4 core clock side XIN blocks of 12 dwords each
+ */
+ unsigned int dwords = (16 * A6XX_NUM_AXI_ARB_BLOCKS) +
+ (18 * A6XX_NUM_XIN_AXI_BLOCKS) +
+ (12 * A6XX_NUM_XIN_CORE_BLOCKS);
+ unsigned int *data = (unsigned int *)(buf + sizeof(*header));
+ size_t size;
+ unsigned int reg_clk;
+
+ size = (dwords * sizeof(unsigned int)) + sizeof(*header);
+
+ if (remain < size) {
+ SNAPSHOT_ERR_NOMEM(device, "DEBUGBUS");
+ return 0;
+ }
+ header->id = block->block_id;
+ header->count = dwords;
+
+ kgsl_regread(device, A6XX_VBIF_CLKON, ®_clk);
+ kgsl_regwrite(device, A6XX_VBIF_CLKON, reg_clk |
+ (A6XX_VBIF_CLKON_FORCE_ON_TESTBUS_MASK <<
+ A6XX_VBIF_CLKON_FORCE_ON_TESTBUS_SHIFT));
+ kgsl_regwrite(device, A6XX_VBIF_TEST_BUS1_CTRL0, 0);
+ kgsl_regwrite(device, A6XX_VBIF_TEST_BUS_OUT_CTRL,
+ (A6XX_VBIF_TEST_BUS_OUT_CTRL_EN_MASK <<
+ A6XX_VBIF_TEST_BUS_OUT_CTRL_EN_SHIFT));
+
+ for (i = 0; i < A6XX_NUM_AXI_ARB_BLOCKS; i++) {
+ kgsl_regwrite(device, A6XX_VBIF_TEST_BUS2_CTRL0,
+ (1 << (i + 16)));
+ for (j = 0; j < 16; j++) {
+ kgsl_regwrite(device, A6XX_VBIF_TEST_BUS2_CTRL1,
+ ((j & A6XX_VBIF_TEST_BUS2_CTRL1_DATA_SEL_MASK)
+ << A6XX_VBIF_TEST_BUS2_CTRL1_DATA_SEL_SHIFT));
+ kgsl_regread(device, A6XX_VBIF_TEST_BUS_OUT,
+ data);
+ data++;
+ }
+ }
+
+ /* XIN blocks AXI side */
+ for (i = 0; i < A6XX_NUM_XIN_AXI_BLOCKS; i++) {
+ kgsl_regwrite(device, A6XX_VBIF_TEST_BUS2_CTRL0, 1 << i);
+ for (j = 0; j < 18; j++) {
+ kgsl_regwrite(device, A6XX_VBIF_TEST_BUS2_CTRL1,
+ ((j & A6XX_VBIF_TEST_BUS2_CTRL1_DATA_SEL_MASK)
+ << A6XX_VBIF_TEST_BUS2_CTRL1_DATA_SEL_SHIFT));
+ kgsl_regread(device, A6XX_VBIF_TEST_BUS_OUT,
+ data);
+ data++;
+ }
+ }
+ kgsl_regwrite(device, A6XX_VBIF_TEST_BUS2_CTRL0, 0);
+
+ /* XIN blocks core clock side */
+ for (i = 0; i < A6XX_NUM_XIN_CORE_BLOCKS; i++) {
+ kgsl_regwrite(device, A6XX_VBIF_TEST_BUS1_CTRL0, 1 << i);
+ for (j = 0; j < 12; j++) {
+ kgsl_regwrite(device, A6XX_VBIF_TEST_BUS1_CTRL1,
+ ((j & A6XX_VBIF_TEST_BUS1_CTRL1_DATA_SEL_MASK)
+ << A6XX_VBIF_TEST_BUS1_CTRL1_DATA_SEL_SHIFT));
+ kgsl_regread(device, A6XX_VBIF_TEST_BUS_OUT,
+ data);
+ data++;
+ }
+ }
+ /* restore the clock of VBIF */
+ kgsl_regwrite(device, A6XX_VBIF_CLKON, reg_clk);
+ return size;
+}
+
static void _cx_dbgc_regread(unsigned int offsetwords, unsigned int *value)
{
void __iomem *reg;
@@ -1310,6 +1399,10 @@
(void *) &a6xx_dbgc_debugbus_blocks[i]);
}
+ kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_DEBUGBUS,
+ snapshot, a6xx_snapshot_vbif_debugbus_block,
+ (void *) &a6xx_vbif_debugbus_blocks);
+
if (a6xx_cx_dbgc) {
for (i = 0; i < ARRAY_SIZE(a6xx_cx_dbgc_debugbus_blocks); i++) {
kgsl_snapshot_add_section(device,
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index f88132f..9ae3cbd 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -989,7 +989,6 @@
*/
kgsl_process_uninit_sysfs(private);
- debugfs_remove_recursive(private->debug_root);
process_release_sync_sources(private);
@@ -1001,12 +1000,14 @@
list_del(&private->list);
/*
- * Unlock the mutex before releasing the memory - this prevents a
- * deadlock with the IOMMU mutex if a page fault occurs
+ * Unlock the mutex before releasing the memory and the debugfs
+ * nodes - this prevents deadlocks with the IOMMU and debugfs
+ * locks.
*/
mutex_unlock(&kgsl_driver.process_mutex);
process_release_memory(private);
+ debugfs_remove_recursive(private->debug_root);
kgsl_process_private_put(private);
}
diff --git a/drivers/gpu/msm/kgsl_pool.c b/drivers/gpu/msm/kgsl_pool.c
index c31a85b..685ce3e 100644
--- a/drivers/gpu/msm/kgsl_pool.c
+++ b/drivers/gpu/msm/kgsl_pool.c
@@ -65,26 +65,19 @@
/* Map the page into kernel and zero it out */
static void
-_kgsl_pool_zero_page(struct page *p, unsigned int pool_order)
+_kgsl_pool_zero_page(struct page *p)
{
- int i;
+ void *addr = kmap_atomic(p);
- for (i = 0; i < (1 << pool_order); i++) {
- struct page *page = nth_page(p, i);
- void *addr = kmap_atomic(page);
-
- memset(addr, 0, PAGE_SIZE);
- dmac_flush_range(addr, addr + PAGE_SIZE);
- kunmap_atomic(addr);
- }
+ memset(addr, 0, PAGE_SIZE);
+ dmac_flush_range(addr, addr + PAGE_SIZE);
+ kunmap_atomic(addr);
}
/* Add a page to specified pool */
static void
_kgsl_pool_add_page(struct kgsl_page_pool *pool, struct page *p)
{
- _kgsl_pool_zero_page(p, pool->pool_order);
-
spin_lock(&pool->list_lock);
list_add_tail(&p->lru, &pool->page_list);
pool->page_count++;
@@ -329,7 +322,6 @@
} else
return -ENOMEM;
}
- _kgsl_pool_zero_page(page, order);
goto done;
}
@@ -349,7 +341,6 @@
page = alloc_pages(gfp_mask, order);
if (page == NULL)
return -ENOMEM;
- _kgsl_pool_zero_page(page, order);
goto done;
}
}
@@ -379,13 +370,12 @@
} else
return -ENOMEM;
}
-
- _kgsl_pool_zero_page(page, order);
}
done:
for (j = 0; j < (*page_size >> PAGE_SHIFT); j++) {
p = nth_page(page, j);
+ _kgsl_pool_zero_page(p);
pages[pcount] = p;
pcount++;
}
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 6710cd2..613fce9 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -224,7 +224,7 @@
{
struct gmu_device *gmu = &device->gmu;
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
- int ret;
+ int ret = 0;
/* GMU scales BW */
if (kgsl_gmu_isenabled(device)) {
@@ -232,7 +232,7 @@
return 0;
ret = gmu_dcvs_set(gmu, INVALID_DCVS_IDX, buslevel);
- } else {
+ } else if (pwr->pcl) {
/* Linux bus driver scales BW */
ret = msm_bus_scale_client_update_request(pwr->pcl, buslevel);
}
@@ -291,7 +291,8 @@
unsigned long ab;
/* the bus should be ON to update the active frequency */
- if (on && !(test_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->power_flags)))
+ if (!(kgsl_gmu_isenabled(device)) && on &&
+ !(test_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->power_flags)))
return;
/*
* If the bus should remain on calculate our request and submit it,
@@ -321,9 +322,7 @@
msm_bus_scale_client_update_request(pwr->ocmem_pcl,
on ? pwr->active_pwrlevel : pwr->num_pwrlevels - 1);
- /* vote for bus if gpubw-dev support is not enabled */
- if (pwr->pcl)
- kgsl_bus_scale_request(device, buslevel);
+ kgsl_bus_scale_request(device, buslevel);
kgsl_pwrctrl_vbif_update(ab);
}
diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c
index e868f92..f2d39a9 100644
--- a/drivers/media/dvb-core/dmxdev.c
+++ b/drivers/media/dvb-core/dmxdev.c
@@ -448,7 +448,7 @@
bytes_read = 0;
}
} else {
- if (bytes_read)
+ if (bytes_read) {
/*
* data was read beyond the non-data event,
* making it not relevant anymore
@@ -459,6 +459,7 @@
if (!(events->event_mask.no_wakeup_mask &
event->type))
events->wakeup_events_counter--;
+ }
}
events->read_index = events->notified_index;
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c b/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c
index a430466..1ee82b5 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c
+++ b/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c
@@ -34,6 +34,11 @@
struct cam_hw_done_event_data *done =
(struct cam_hw_done_event_data *)done_event_data;
+ if (!ctx || !done) {
+ CAM_ERR(CAM_CTXT, "Invalid input params %pK %pK", ctx, done);
+ return -EINVAL;
+ }
+
if (list_empty(&ctx->active_req_list)) {
CAM_ERR(CAM_CTXT, "no active request");
return -EIO;
@@ -78,6 +83,12 @@
struct cam_ctx_request *req;
struct cam_hw_config_args cfg;
+ if (!ctx || !apply) {
+ CAM_ERR(CAM_CTXT, "Invalid input params %pK %pK", ctx, apply);
+ rc = -EINVAL;
+ goto end;
+ }
+
if (!ctx->hw_mgr_intf) {
CAM_ERR(CAM_CTXT, "HW interface is not ready");
rc = -EFAULT;
@@ -119,6 +130,11 @@
struct cam_ctx_request *req = NULL;
struct cam_req_mgr_apply_request apply;
+ if (!ctx) {
+ CAM_ERR(CAM_CTXT, "Invalid input param");
+ return;
+ }
+
spin_lock(&ctx->lock);
if (!list_empty(&ctx->pending_req_list))
req = list_first_entry(&ctx->pending_req_list,
@@ -144,6 +160,11 @@
struct cam_hw_release_args arg;
struct cam_ctx_request *req;
+ if (!ctx) {
+ CAM_ERR(CAM_CTXT, "Invalid input param");
+ return -EINVAL;
+ }
+
if ((!ctx->hw_mgr_intf) || (!ctx->hw_mgr_intf->hw_release)) {
CAM_ERR(CAM_CTXT, "HW interface is not ready");
return -EINVAL;
@@ -209,6 +230,12 @@
size_t len = 0;
int32_t i = 0;
+ if (!ctx || !cmd) {
+ CAM_ERR(CAM_CTXT, "Invalid input params %pK %pK", ctx, cmd);
+ rc = -EINVAL;
+ goto end;
+ }
+
if (!ctx->hw_mgr_intf) {
CAM_ERR(CAM_CTXT, "HW interface is not ready");
rc = -EFAULT;
@@ -304,6 +331,12 @@
struct cam_create_dev_hdl req_hdl_param;
struct cam_hw_release_args release;
+ if (!ctx || !cmd) {
+ CAM_ERR(CAM_CTXT, "Invalid input params %pK %pK", ctx, cmd);
+ rc = -EINVAL;
+ goto end;
+ }
+
if (!ctx->hw_mgr_intf) {
CAM_ERR(CAM_CTXT, "HW interface is not ready");
rc = -EFAULT;
@@ -377,6 +410,12 @@
int rc = 0;
struct cam_hw_start_args arg;
+ if (!ctx || !cmd) {
+ CAM_ERR(CAM_CTXT, "Invalid input params %pK %pK", ctx, cmd);
+ rc = -EINVAL;
+ goto end;
+ }
+
if (!ctx->hw_mgr_intf) {
CAM_ERR(CAM_CTXT, "HW interface is not ready");
rc = -EFAULT;
@@ -392,6 +431,7 @@
}
if (ctx->hw_mgr_intf->hw_start) {
+ arg.ctxt_to_hw_map = ctx->ctxt_to_hw_map;
rc = ctx->hw_mgr_intf->hw_start(ctx->hw_mgr_intf->hw_mgr_priv,
&arg);
if (rc) {
@@ -412,6 +452,12 @@
struct cam_hw_stop_args stop;
struct cam_ctx_request *req;
+ if (!ctx) {
+ CAM_ERR(CAM_CTXT, "Invalid input param");
+ rc = -EINVAL;
+ goto end;
+ }
+
if (!ctx->hw_mgr_intf) {
CAM_ERR(CAM_CTXT, "HW interface is not ready");
rc = -EFAULT;
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c
index f37ec38..5d7a1b9 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c
@@ -650,6 +650,8 @@
switch (out_fmt) {
case CAM_FORMAT_NV21:
case CAM_FORMAT_NV12:
+ case CAM_FORMAT_UBWC_NV12:
+ case CAM_FORMAT_UBWC_NV12_4R:
return PACKER_FMT_PLAIN_8_LSB_MSB_10;
case CAM_FORMAT_PLAIN64:
return PACKER_FMT_PLAIN_64;
@@ -660,10 +662,6 @@
case CAM_FORMAT_MIPI_RAW_14:
case CAM_FORMAT_MIPI_RAW_16:
case CAM_FORMAT_MIPI_RAW_20:
- case CAM_FORMAT_QTI_RAW_8:
- case CAM_FORMAT_QTI_RAW_10:
- case CAM_FORMAT_QTI_RAW_12:
- case CAM_FORMAT_QTI_RAW_14:
case CAM_FORMAT_PLAIN128:
case CAM_FORMAT_PLAIN8:
case CAM_FORMAT_PLAIN16_8:
@@ -675,6 +673,9 @@
case CAM_FORMAT_PD8:
case CAM_FORMAT_PD10:
return PACKER_FMT_PLAIN_128;
+ case CAM_FORMAT_UBWC_TP10:
+ case CAM_FORMAT_TP10:
+ return PACKER_FMT_TP_10;
default:
return PACKER_FMT_MAX;
}
@@ -721,6 +722,7 @@
rsrc_data->height = out_port_info->height;
if (rsrc_data->index < 3) {
+ /* Write master 0-2 refers to RDI 0/ RDI 1/RDI 2 */
rsrc_data->width = CAM_VFE_RDI_BUS_DEFAULT_WIDTH;
rsrc_data->height = 0;
rsrc_data->stride = CAM_VFE_RDI_BUS_DEFAULT_STRIDE;
@@ -728,50 +730,59 @@
rsrc_data->en_cfg = 0x3;
} else if (rsrc_data->index < 5 ||
rsrc_data->index == 7 || rsrc_data->index == 8) {
- switch (plane) {
- case PLANE_Y:
- switch (rsrc_data->format) {
- case CAM_FORMAT_UBWC_NV12:
- case CAM_FORMAT_UBWC_NV12_4R:
- case CAM_FORMAT_UBWC_TP10:
- rsrc_data->en_ubwc = 1;
+ /* Write master 3, 4 - for Full OUT , 7-8 FD OUT */
+ switch (rsrc_data->format) {
+ case CAM_FORMAT_UBWC_NV12:
+ case CAM_FORMAT_UBWC_NV12_4R:
+ rsrc_data->en_ubwc = 1;
+ /* Fall through for NV12 */
+ case CAM_FORMAT_NV21:
+ case CAM_FORMAT_NV12:
+ switch (plane) {
+ case PLANE_C:
+ rsrc_data->height /= 2;
+ break;
+ case PLANE_Y:
break;
default:
- break;
+ CAM_ERR(CAM_ISP, "Invalid plane %d\n", plane);
+ return -EINVAL;
}
break;
- case PLANE_C:
- switch (rsrc_data->format) {
- case CAM_FORMAT_NV21:
- case CAM_FORMAT_NV12:
+ case CAM_FORMAT_UBWC_TP10:
+ rsrc_data->en_ubwc = 1;
+ /* Fall through for LINEAR TP10 */
+ case CAM_FORMAT_TP10:
+ rsrc_data->width = rsrc_data->width * 4 / 3;
+ switch (plane) {
+ case PLANE_C:
rsrc_data->height /= 2;
break;
- case CAM_FORMAT_UBWC_NV12:
- case CAM_FORMAT_UBWC_NV12_4R:
- case CAM_FORMAT_UBWC_TP10:
- rsrc_data->height /= 2;
- rsrc_data->en_ubwc = 1;
+ case PLANE_Y:
break;
default:
- break;
+ CAM_ERR(CAM_ISP, "Invalid plane %d\n", plane);
+ return -EINVAL;
}
break;
default:
- CAM_ERR(CAM_ISP, "Invalid plane type %d", plane);
+ CAM_ERR(CAM_ISP, "Invalid format %d\n",
+ rsrc_data->format);
return -EINVAL;
}
rsrc_data->en_cfg = 0x1;
} else if (rsrc_data->index >= 11) {
+ /* Write master 11-19 stats */
rsrc_data->width = 0;
rsrc_data->height = 0;
rsrc_data->stride = 1;
rsrc_data->en_cfg = 0x3;
} else {
+ /* Write master 5-6 DS ports , 9 - Raw dump , 10 PDAF */
rsrc_data->width = rsrc_data->width * 4;
rsrc_data->height = rsrc_data->height / 2;
rsrc_data->en_cfg = 0x1;
}
-
if (vfe_out_res_id >= CAM_ISP_IFE_OUT_RES_RDI_0 &&
vfe_out_res_id <= CAM_ISP_IFE_OUT_RES_RDI_3)
rsrc_data->frame_based = 1;
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c
index c69eeaa..975b301 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c
@@ -145,13 +145,13 @@
void __iomem *base = soc_info->reg_map[0].mem_base;
if (!cci_dev) {
- CAM_ERR(CAM_CCI, "%s: failed %d");
+ CAM_ERR(CAM_CCI, "Failed");
return -EINVAL;
}
rc = cam_cci_validate_queue(cci_dev, 1, master, queue);
if (rc < 0) {
- CAM_ERR(CAM_CCI, "Failed %d");
+ CAM_ERR(CAM_CCI, "Failed %d", rc);
return rc;
}
CAM_DBG(CAM_CCI, "CCI_I2C_M0_Q0_LOAD_DATA_ADDR:val 0x%x:0x%x",
@@ -184,42 +184,43 @@
uint32_t reg_offset = 0;
/* CCI Top Registers */
- CCI_DBG(" **** %s : %d CCI TOP Registers ****");
+ CAM_DBG(CAM_CCI, "****CCI TOP Registers ****");
for (i = 0; i < DEBUG_TOP_REG_COUNT; i++) {
reg_offset = DEBUG_TOP_REG_START + i * 4;
read_val = cam_io_r_mb(cci_dev->base + reg_offset);
- CCI_DBG("offset = 0x%X value = 0x%X",
+ CAM_DBG(CAM_CCI, "offset = 0x%X value = 0x%X",
reg_offset, read_val);
}
/* CCI Master registers */
- CCI_DBG(" ****CCI MASTER %d Registers ****",
+ CAM_DBG(CAM_CCI, "****CCI MASTER %d Registers ****",
master);
for (i = 0; i < DEBUG_MASTER_REG_COUNT; i++) {
if (i == 6)
continue;
reg_offset = DEBUG_MASTER_REG_START + master*0x100 + i * 4;
read_val = cam_io_r_mb(cci_dev->base + reg_offset);
- CCI_DBG("offset = 0x%X value = 0x%X", reg_offset, read_val);
+ CAM_DBG(CAM_CCI, "offset = 0x%X value = 0x%X",
+ reg_offset, read_val);
}
/* CCI Master Queue registers */
- CCI_DBG(" **** CCI MASTER%d QUEUE%d Registers ****",
+ CAM_DBG(CAM_CCI, " **** CCI MASTER%d QUEUE%d Registers ****",
master, queue);
for (i = 0; i < DEBUG_MASTER_QUEUE_REG_COUNT; i++) {
reg_offset = DEBUG_MASTER_QUEUE_REG_START + master*0x200 +
queue*0x100 + i * 4;
read_val = cam_io_r_mb(cci_dev->base + reg_offset);
- CCI_DBG("offset = 0x%X value = 0x%X",
+ CAM_DBG(CAM_CCI, "offset = 0x%X value = 0x%X",
reg_offset, read_val);
}
/* CCI Interrupt registers */
- CCI_DBG(" ****CCI Interrupt Registers ****");
+ CAM_DBG(CAM_CCI, " ****CCI Interrupt Registers ****");
for (i = 0; i < DEBUG_INTR_REG_COUNT; i++) {
reg_offset = DEBUG_INTR_REG_START + i * 4;
read_val = cam_io_r_mb(cci_dev->base + reg_offset);
- CCI_DBG("offset = 0x%X value = 0x%X",
+ CAM_DBG(CAM_CCI, "offset = 0x%X value = 0x%X",
reg_offset, read_val);
}
}
@@ -449,8 +450,7 @@
}
if (len > cci_dev->payload_size) {
- CAM_ERR(CAM_CCI, "%s: %d Len error: %d",
- len);
+ CAM_ERR(CAM_CCI, "Len error: %d", len);
return -EINVAL;
}
@@ -660,7 +660,7 @@
rc = cam_cci_lock_queue(cci_dev, master, queue, 1);
if (rc < 0) {
- CAM_ERR(CAM_CCI, "%s failed line %d");
+ CAM_ERR(CAM_CCI, "failed line %d", rc);
return rc;
}
@@ -670,7 +670,7 @@
len = cam_cci_calc_cmd_len(cci_dev, c_ctrl, cmd_size,
i2c_cmd, &pack);
if (len <= 0) {
- CAM_ERR(CAM_CCI, "%s failed line %d");
+ CAM_ERR(CAM_CCI, "failed");
return -EINVAL;
}
@@ -918,7 +918,7 @@
val = cam_io_r_mb(base + CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR
+ master * 0x200 + queue * 0x100);
- CAM_DBG(CAM_CCI, "%s cur word cnt 0x%x", val);
+ CAM_DBG(CAM_CCI, "cur word cnt 0x%x", val);
cam_io_w_mb(val, base + CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR
+ master * 0x200 + queue * 0x100);
@@ -989,7 +989,7 @@
cci_dev = v4l2_get_subdevdata(sd);
if (cci_dev->cci_state != CCI_STATE_ENABLED) {
- CAM_ERR(CAM_CCI, "%s invalid cci state %d",
+ CAM_ERR(CAM_CCI, "invalid cci state %d",
cci_dev->cci_state);
return -EINVAL;
}
@@ -1013,8 +1013,8 @@
cci_dev->cci_i2c_queue_info[master][queue].max_queue_size-1,
master, queue);
if (rc < 0) {
- CAM_ERR(CAM_CCI, "%s:%d Initial validataion failed rc %d",
- rc);
+ CAM_ERR(CAM_CCI, "Initial validataion failed rc %d",
+ rc);
return rc;
}
if (c_ctrl->cci_info->retries > CCI_I2C_READ_MAX_RETRIES) {
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.c
index 1453fb3..40cf689 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.c
@@ -27,7 +27,7 @@
rc = cam_sensor_driver_cmd(s_ctrl, arg);
break;
default:
- CAM_ERR(CAM_SENSOR, " Invalid ioctl cmd: %d", cmd);
+ CAM_ERR(CAM_SENSOR, "Invalid ioctl cmd: %d", cmd);
rc = -EINVAL;
break;
}
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_soc.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_soc.c
index c2f1b4d..c10d634 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_soc.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_soc.c
@@ -218,7 +218,6 @@
/* Initialize mutex */
mutex_init(&(s_ctrl->cam_sensor_mutex));
- CAM_DBG(CAM_SENSOR, "%s: %d");
/* Initialize default parameters */
for (i = 0; i < soc_info->num_clk; i++) {
soc_info->clk[i] = devm_clk_get(&soc_info->pdev->dev,
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c
index 915e2f7..ca648f01 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c
@@ -206,7 +206,6 @@
int32_t rc = 0;
struct cam_cci_ctrl cci_ctrl;
- CAM_DBG(CAM_SENSOR, "%s line %d");
cci_ctrl.cmd = cci_cmd;
cci_ctrl.cci_info = cci_client;
rc = v4l2_subdev_call(cci_client->cci_subdev,
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c
index 9e38e1a..154f4ad 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c
@@ -10,14 +10,9 @@
* GNU General Public License for more details.
*/
-#define pr_fmt(fmt) "CAM-SENSOR_IO %s:%d " fmt, __func__, __LINE__
-
#include "cam_sensor_io.h"
#include "cam_sensor_i2c.h"
-#undef CDBG
-#define CDBG(fmt, args...) pr_debug(fmt, ##args)
-
int32_t camera_io_dev_poll(struct camera_io_master *io_master_info,
uint32_t addr, uint16_t data, uint32_t data_mask,
enum camera_sensor_i2c_type data_type,
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_qup_i2c.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_qup_i2c.c
index b64e0d0..72e51ee 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_qup_i2c.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_qup_i2c.c
@@ -40,7 +40,7 @@
};
rc = i2c_transfer(dev_client->adapter, msgs, 2);
if (rc < 0)
- CAM_ERR(CAM_SENSOR, "%s:failed 0x%x", saddr);
+ CAM_ERR(CAM_SENSOR, "failed 0x%x", saddr);
return rc;
}
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_spi.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_spi.c
index e0b737e..4011aa0 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_spi.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_spi.c
@@ -220,7 +220,7 @@
msleep(client->spi_client->retry_delay);
}
if (rc < 0) {
- pr_err("%s: failed %d\n", __func__, rc);
+ CAM_ERR(CAM_SENSOR, "failed %d", rc);
goto out;
}
if (data && num_byte && !rx)
@@ -248,7 +248,7 @@
&client->spi_client->cmd_tbl.read, addr, &temp[0],
data_type, NULL, NULL);
if (rc < 0) {
- pr_err("%s: failed %d\n", __func__, rc);
+ CAM_ERR(CAM_SENSOR, "failed %d", rc);
return rc;
}
@@ -257,7 +257,7 @@
else
*data = (temp[0] << BITS_PER_BYTE) | temp[1];
- CAM_DBG(CAM_SENSOR, "addr 0x%x, data %u\n", addr, *data);
+ CAM_DBG(CAM_SENSOR, "addr 0x%x, data %u", addr, *data);
return rc;
}
@@ -276,8 +276,8 @@
&client->spi_client->cmd_tbl.read_status;
if (rs->addr_len != 0) {
- pr_err("%s: not implemented yet\n", __func__);
- return -EINVAL;
+ CAM_ERR(CAM_SENSOR, "not implemented yet");
+ return -ENXIO;
}
return cam_spi_tx_helper(client, rs, 0, status, 1, NULL, NULL);
}
@@ -290,7 +290,7 @@
rc = cam_spi_read_status_reg(client, &st);
if (rc < 0) {
- pr_err("%s: failed to read status reg\n", __func__);
+ CAM_ERR(CAM_SENSOR, "failed to read status reg");
return rc;
}
*busy = st & client->spi_client->busy_mask;
@@ -314,7 +314,7 @@
CAM_DBG(CAM_SENSOR, "op 0x%x wait", inst->opcode);
}
if (i > inst->delay_count) {
- pr_err("%s: op %x timed out\n", __func__, inst->opcode);
+ CAM_ERR(CAM_SENSOR, "op %x timed out", inst->opcode);
return -ETIMEDOUT;
}
CAM_DBG(CAM_SENSOR, "op %x finished", inst->opcode);
@@ -331,12 +331,12 @@
if (we->opcode == 0)
return 0;
if (we->addr_len != 0) {
- pr_err("%s: not implemented yet\n", __func__);
+ CAM_ERR(CAM_SENSOR, "not implemented yet");
return -EINVAL;
}
rc = cam_spi_tx_helper(client, we, 0, NULL, 0, NULL, NULL);
if (rc < 0)
- pr_err("%s: write enable failed\n", __func__);
+ CAM_ERR(CAM_SENSOR, "write enable failed");
return rc;
}
@@ -372,7 +372,7 @@
tx[0] = pg->opcode;
cam_set_addr(addr, pg->addr_len, addr_type, tx + 1);
memcpy(tx + header_len, data, len);
- CAM_DBG(CAM_SENSOR, "tx(%u): %02x %02x %02x %02x\n",
+ CAM_DBG(CAM_SENSOR, "tx(%u): %02x %02x %02x %02x",
len, tx[0], tx[1], tx[2], tx[3]);
while ((rc = spi_write(spi, tx, len + header_len)) && retries) {
rc = cam_spi_wait(client, pg);
@@ -380,7 +380,7 @@
retries--;
}
if (rc < 0) {
- pr_err("%s: failed %d\n", __func__, rc);
+ CAM_ERR(CAM_SENSOR, "failed %d", rc);
return rc;
}
rc = cam_spi_wait(client, pg);
@@ -422,10 +422,10 @@
goto ERROR;
goto OUT;
NOMEM:
- pr_err("%s: memory allocation failed\n", __func__);
+ CAM_ERR(CAM_SENSOR, "memory allocation failed");
return -ENOMEM;
ERROR:
- pr_err("%s: error write\n", __func__);
+ CAM_ERR(CAM_SENSOR, "error write");
OUT:
kfree(tx);
return rc;
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c
index 06590e4..b1698ca 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c
@@ -903,7 +903,7 @@
gconf->cam_gpio_common_tbl[val].gpio;
gpio_num_info->valid[SENSOR_VANA] = 1;
- CAM_DBG(CAM_SENSOR, "%s:%d gpio-vana %d",
+ CAM_DBG(CAM_SENSOR, "gpio-vana %d",
gpio_num_info->gpio_num[SENSOR_VANA]);
}
diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c
index 1990230..e5c7dbb 100644
--- a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c
+++ b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c
@@ -128,6 +128,30 @@
return 0;
}
+long cam_soc_util_get_clk_round_rate(struct cam_hw_soc_info *soc_info,
+ uint32_t clk_index, unsigned long clk_rate)
+{
+ if (!soc_info || (clk_index >= soc_info->num_clk) || (clk_rate == 0)) {
+ CAM_ERR(CAM_UTIL, "Invalid input params %pK, %d %lld",
+ soc_info, clk_index, clk_rate);
+ return clk_rate;
+ }
+
+ return clk_round_rate(soc_info->clk[clk_index], clk_rate);
+}
+
+int cam_soc_util_set_clk_flags(struct cam_hw_soc_info *soc_info,
+ uint32_t clk_index, unsigned long flags)
+{
+ if (!soc_info || (clk_index >= soc_info->num_clk)) {
+ CAM_ERR(CAM_UTIL, "Invalid input params %pK, %d",
+ soc_info, clk_index);
+ return -EINVAL;
+ }
+
+ return clk_set_flags(soc_info->clk[clk_index], flags);
+}
+
int cam_soc_util_set_clk_rate(struct clk *clk, const char *clk_name,
int32_t clk_rate)
{
diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h
index 7eb7578..ae92cab 100644
--- a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h
+++ b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h
@@ -19,6 +19,7 @@
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
+#include <linux/clk/qcom.h>
#include "cam_io_util.h"
@@ -328,6 +329,35 @@
bool disable_clocks, bool disable_irq);
/**
+ * cam_soc_util_get_clk_round_rate()
+ *
+ * @brief: Get the rounded clock rate for the given clock's
+ * clock rate value
+ *
+ * @soc_info: Device soc information
+ * @clk_index: Clock index in soc_info for which round rate is needed
+ * @clk_rate: Input clock rate for which rounded rate is needed
+ *
+ * @return: Rounded clock rate
+ */
+long cam_soc_util_get_clk_round_rate(struct cam_hw_soc_info *soc_info,
+ uint32_t clk_index, unsigned long clk_rate);
+
+/**
+ * cam_soc_util_set_clk_flags()
+ *
+ * @brief: Camera SOC util to set the flags for a specified clock
+ *
+ * @soc_info: Device soc information
+ * @clk_index: Clock index in soc_info for which flags are to be set
+ * @flags: Flags to set
+ *
+ * @return: Success or Failure
+ */
+int cam_soc_util_set_clk_flags(struct cam_hw_soc_info *soc_info,
+ uint32_t clk_index, unsigned long flags);
+
+/**
* cam_soc_util_set_clk_rate()
*
* @brief: Set the rate on a given clock.
diff --git a/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c b/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c
index a7b1852..a93f054 100644
--- a/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c
+++ b/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c
@@ -330,7 +330,9 @@
*/
/* Decoder parameters */
int width, height, lcu_size, dpb_bpp, opb_bpp, fps, opb_factor;
- bool unified_dpb_opb, dpb_compression_enabled, opb_compression_enabled;
+ bool unified_dpb_opb, dpb_compression_enabled, opb_compression_enabled,
+ llc_ref_read_l2_cache_enabled = false,
+ llc_vpss_ds_line_buf_enabled = false;
fp_t dpb_opb_scaling_ratio, dpb_read_compression_factor,
dpb_write_compression_factor, opb_compression_factor,
qsmmu_bw_overhead_factor, height_ratio;
@@ -342,7 +344,8 @@
fp_t bins_to_bit_factor, dpb_write_factor, ten_bpc_packing_factor,
ten_bpc_bpp_factor, vsp_read_factor, vsp_write_factor,
bw_for_1x_8bpc, dpb_bw_for_1x,
- motion_vector_complexity = 0, row_cache_penalty = 0, opb_bw = 0;
+ motion_vector_complexity = 0, row_cache_penalty = 0, opb_bw = 0,
+ dpb_total = 0;
/* Output parameters */
struct {
@@ -352,6 +355,10 @@
total;
} ddr = {0};
+ struct {
+ fp_t dpb_read, opb_read, total;
+ } llc = {0};
+
unsigned long ret = 0;
unsigned int integer_part, frac_part;
@@ -407,6 +414,11 @@
opb_compression_factor = !opb_compression_enabled ? FP_ONE :
__compression_ratio(__lut(width, height, fps), opb_bpp);
+ llc_ref_read_l2_cache_enabled = llc_vpss_ds_line_buf_enabled = false;
+ if (d->use_sys_cache) {
+ llc_ref_read_l2_cache_enabled = true;
+ llc_vpss_ds_line_buf_enabled = true;
+ }
/* Derived parameters setup */
lcu_per_frame = DIV_ROUND_UP(width, lcu_size) *
@@ -462,6 +474,12 @@
ddr.dpb_write = fp_div(fp_mult(dpb_bw_for_1x, dpb_write_factor),
dpb_write_compression_factor);
+ dpb_total = ddr.dpb_read + ddr.dpb_write;
+ if (llc_ref_read_l2_cache_enabled) {
+ row_cache_penalty = FP(1, 30, 100);
+ ddr.dpb_read = fp_div(ddr.dpb_read, row_cache_penalty);
+ llc.dpb_read = dpb_total - ddr.dpb_read;
+ }
opb_factor = dpb_bpp == 8 ? 8 : 4;
@@ -473,6 +491,11 @@
FP(1, 50, 100)), dpb_opb_scaling_ratio),
opb_compression_factor);
+ if (llc_vpss_ds_line_buf_enabled) {
+ llc.opb_read = ddr.opb_read;
+ ddr.opb_write -= ddr.opb_read;
+ ddr.opb_read = 0;
+ }
ddr.total = ddr.vsp_read + ddr.vsp_write +
ddr.collocated_read + ddr.collocated_write +
ddr.opb_read + ddr.opb_write +
@@ -481,6 +504,7 @@
qsmmu_bw_overhead_factor = FP(1, 3, 100);
ddr.total = fp_mult(ddr.total, qsmmu_bw_overhead_factor);
+ llc.total = llc.dpb_read + llc.opb_read;
/* Dump all the variables for easier debugging */
if (debug) {
@@ -521,6 +545,8 @@
{"DERIVED PARAMETERS (2)", "", DUMP_HEADER_MAGIC},
{"MV complexity", DUMP_FP_FMT, motion_vector_complexity},
{"row cache penalty", DUMP_FP_FMT, row_cache_penalty},
+ {"qsmmu_bw_overhead_factor", DUMP_FP_FMT,
+ qsmmu_bw_overhead_factor},
{"OPB B/W (single instance)", DUMP_FP_FMT, opb_bw},
{"INTERMEDIATE DDR B/W", "", DUMP_HEADER_MAGIC},
@@ -536,6 +562,8 @@
{"OPB write", DUMP_FP_FMT, ddr.opb_write},
{"DPB read", DUMP_FP_FMT, ddr.dpb_read},
{"DPB write", DUMP_FP_FMT, ddr.dpb_write},
+ {"LLC DPB read", DUMP_FP_FMT, llc.dpb_read},
+ {"LLC OPB read", DUMP_FP_FMT, llc.opb_read},
};
__dump(dump, ARRAY_SIZE(dump));
@@ -546,7 +574,7 @@
ret = kbps(fp_round(ddr.total));
break;
case GOVERNOR_LLCC:
- dprintk(VIDC_PROF, "LLCC Voting not supported yet\n");
+ ret = kbps(fp_round(llc.total));
break;
default:
dprintk(VIDC_ERR, "%s - Unknown governor\n", __func__);
@@ -565,32 +593,25 @@
*/
/* Encoder Parameters */
- enum hal_video_codec standard;
- int width, height, fps;
- enum hal_uncompressed_format dpb_color_format;
- enum hal_uncompressed_format original_color_format;
+ int width, height, fps, dpb_bpp, lcu_per_frame, lcu_size,
+ vertical_tile_width, colocated_bytes_per_lcu, bitrate,
+ ref_overlap_bw_factor;
+ enum hal_uncompressed_format dpb_color_format, original_color_format;
bool dpb_compression_enabled, original_compression_enabled,
- two_stage_encoding, low_power, rotation, cropping_or_scaling;
+ work_mode_1, low_power, rotation, cropping_or_scaling,
+ b_frames_enabled = false,
+ llc_dual_core_ref_read_buf_enabled = false,
+ llc_top_line_buf_enabled = false,
+ llc_ref_chroma_cache_enabled = false;
fp_t dpb_compression_factor, original_compression_factor,
- qsmmu_bw_overhead_factor;
- bool b_frames_enabled;
-
- /* Derived Parameters */
- int lcu_size;
- enum gop {
- GOP_IBBP,
- GOP_IPPP,
- } gop;
- unsigned long bitrate;
- fp_t bins_to_bit_factor, chroma_luma_factor_dpb, one_frame_bw_dpb,
- chroma_luma_factor_original, one_frame_bw_original,
- line_buffer_size_per_lcu, line_buffer_size, line_buffer_bw,
- bw_increase_p, bw_increase_b;
- int collocated_mv_per_lcu, max_transaction_size,
- search_window_size_vertical_p, search_window_factor_p,
- search_window_factor_bw_p,
- search_window_size_vertical_b, search_window_factor_b,
- search_window_factor_bw_b;
+ input_compression_factor, qsmmu_bw_overhead_factor,
+ ref_y_bw_factor, ref_cb_cr_bw_factor, ten_bpc_bpp_factor,
+ bw_for_1x_8bpc, dpb_bw_for_1x, ref_cb_cr_read,
+ bins_to_bit_factor, ref_y_read, ten_bpc_packing_factor,
+ dpb_write_factor, ref_overlap_bw, llc_ref_y_read,
+ llc_ref_cb_cr_read;
+ fp_t integer_part, frac_part;
+ unsigned long ret = 0;
/* Output paramaters */
struct {
@@ -599,27 +620,49 @@
original_write, dpb_read, dpb_write, total;
} ddr = {0};
- unsigned long ret = 0;
- fp_t integer_part, frac_part;
+ struct {
+ fp_t dpb_read, line_buffer, total;
+ } llc = {0};
/* Encoder Parameters setup */
+ ten_bpc_packing_factor = FP(1, 67, 1000);
+ ten_bpc_bpp_factor = FP(1, 1, 4);
+ rotation = false;
+ cropping_or_scaling = false;
+ vertical_tile_width = 960;
+ ref_y_bw_factor = FP(1, 30, 100);
+ ref_cb_cr_bw_factor = FP(1, 50, 100);
+ dpb_write_factor = FP(1, 8, 100);
- standard = d->codec;
+
+ /* Derived Parameters */
+ lcu_size = d->lcu_size;
+ fps = d->fps;
+ b_frames_enabled = d->b_frames_enabled;
width = max(d->input_width, BASELINE_DIMENSIONS.width);
height = max(d->input_height, BASELINE_DIMENSIONS.height);
+ bitrate = __lut(width, height, fps)->bitrate;
+ lcu_per_frame = DIV_ROUND_UP(width, lcu_size) *
+ DIV_ROUND_UP(height, lcu_size);
dpb_color_format = HAL_COLOR_FORMAT_NV12_UBWC;
original_color_format = d->num_formats >= 1 ?
d->color_formats[0] : HAL_UNUSED_COLOR;
- fps = d->fps;
+ dpb_bpp = d->num_formats >= 1 ? __bpp(d->color_formats[0]) : INT_MAX;
dpb_compression_enabled = __ubwc(dpb_color_format);
original_compression_enabled = __ubwc(original_color_format);
- two_stage_encoding = false;
+ work_mode_1 = d->work_mode == VIDC_WORK_MODE_1;
low_power = d->power_mode == VIDC_POWER_LOW;
- b_frames_enabled = false;
+ bins_to_bit_factor = work_mode_1 ?
+ FP_INT(0) : FP_INT(4);
+
+ if (d->use_sys_cache) {
+ llc_dual_core_ref_read_buf_enabled = true;
+ llc_ref_chroma_cache_enabled = true;
+ }
/*
* Convert Q16 number into Integer and Fractional part upto 2 places.
@@ -636,96 +679,106 @@
dpb_compression_factor = FP(integer_part, frac_part, 100);
- original_compression_factor = dpb_compression_factor;
+ integer_part = d->input_cr >> 16;
+ frac_part =
+ ((d->input_cr - (integer_part * 65536)) * 100) >> 16;
- rotation = false;
- cropping_or_scaling = false;
+ input_compression_factor = FP(integer_part, frac_part, 100);
- /* Derived Parameters */
- lcu_size = 16;
- gop = b_frames_enabled ? GOP_IBBP : GOP_IPPP;
- bitrate = __lut(width, height, fps)->bitrate;
- bins_to_bit_factor = FP(1, 6, 10);
+ original_compression_factor =
+ original_compression_enabled ? d->use_dpb_read ?
+ dpb_compression_factor : input_compression_factor :
+ FP_ONE;
- /*
- * FIXME: Minor color format related hack: a lot of the derived params
- * depend on the YUV bitdepth as a variable. However, we don't have
- * appropriate enums defined yet (hence no support). As a result omit
- * a lot of the checks (which should look like the snippet below) in
- * favour of hardcoding.
- * dpb_color_format == YUV420 ? 0.5 :
- * dpb_color_format == YUV422 ? 1.0 : 2.0
- * Similar hacks are annotated inline in code with the string "CF hack"
- * for documentation purposes.
- */
- chroma_luma_factor_dpb = FP(0, 1, 2);
- one_frame_bw_dpb = fp_mult(FP_ONE + chroma_luma_factor_dpb,
- fp_div(FP_INT(width * height * fps),
- FP_INT(1000 * 1000)));
-
- chroma_luma_factor_original = FP(0, 1, 2); /* XXX: CF hack */
- one_frame_bw_original = fp_mult(FP_ONE + chroma_luma_factor_original,
- fp_div(FP_INT(width * height * fps),
- FP_INT(1000 * 1000)));
-
- line_buffer_size_per_lcu = FP_ZERO;
- if (lcu_size == 16)
- line_buffer_size_per_lcu = FP_INT(128) + fp_mult(FP_INT(256),
- FP_ONE /*XXX: CF hack */);
- else
- line_buffer_size_per_lcu = FP_INT(192) + fp_mult(FP_INT(512),
- FP_ONE /*XXX: CF hack */);
-
- line_buffer_size = fp_div(
- fp_mult(FP_INT(width / lcu_size),
- line_buffer_size_per_lcu),
- FP_INT(1024));
- line_buffer_bw = fp_mult(line_buffer_size,
- fp_div(FP_INT((height / lcu_size /
- (two_stage_encoding ? 2 : 1) - 1) * fps),
- FP_INT(1000)));
-
- collocated_mv_per_lcu = lcu_size == 16 ? 16 : 64;
- max_transaction_size = 256;
-
- search_window_size_vertical_p = low_power ? 32 :
- b_frames_enabled ? 80 :
- width > 2048 ? 64 : 48;
- search_window_factor_p = search_window_size_vertical_p * 2 / lcu_size;
- search_window_factor_bw_p = !two_stage_encoding ?
- search_window_size_vertical_p * 2 / lcu_size + 1 :
- (search_window_size_vertical_p * 2 / lcu_size + 2) / 2;
- bw_increase_p = fp_mult(one_frame_bw_dpb,
- FP_INT(search_window_factor_bw_p - 1) / 3);
-
- search_window_size_vertical_b = 48;
- search_window_factor_b = search_window_size_vertical_b * 2 / lcu_size;
- search_window_factor_bw_b = !two_stage_encoding ?
- search_window_size_vertical_b * 2 / lcu_size + 1 :
- (search_window_size_vertical_b * 2 / lcu_size + 2) / 2;
- bw_increase_b = fp_mult(one_frame_bw_dpb,
- FP_INT((search_window_factor_bw_b - 1) / 3));
-
- /* Output parameters for DDR */
ddr.vsp_read = fp_mult(fp_div(FP_INT(bitrate), FP_INT(8)),
bins_to_bit_factor);
ddr.vsp_write = ddr.vsp_read + fp_div(FP_INT(bitrate), FP_INT(8));
- ddr.collocated_read = fp_div(FP_INT(DIV_ROUND_UP(width, lcu_size) *
- DIV_ROUND_UP(height, lcu_size) *
- collocated_mv_per_lcu * fps), FP_INT(1000 * 1000));
+ colocated_bytes_per_lcu = lcu_size == 16 ? 16 :
+ lcu_size == 32 ? 64 : 256;
+
+ ddr.collocated_read = FP_INT(lcu_per_frame *
+ colocated_bytes_per_lcu * fps / bps(1));
+
ddr.collocated_write = ddr.collocated_read;
+ ddr.line_buffer_read = FP_INT(16 * lcu_per_frame * fps / bps(1));
+
ddr.line_buffer_write = ddr.line_buffer_read;
- ddr.original_read = fp_div(one_frame_bw_original,
- original_compression_factor);
+ llc.line_buffer = ddr.line_buffer_read + ddr.line_buffer_write;
+ if (llc_top_line_buf_enabled)
+ ddr.line_buffer_read = ddr.line_buffer_write = FP_INT(0);
+
+ llc.line_buffer -= (ddr.line_buffer_read + ddr.line_buffer_write);
+
+ bw_for_1x_8bpc = fp_div(FP_INT(width * height), FP_INT(32 * 8));
+
+ bw_for_1x_8bpc = fp_mult(bw_for_1x_8bpc,
+ fp_div(FP_INT(256 * 30), FP_INT(1000 * 1000)));
+
+ dpb_bw_for_1x = dpb_bpp == 8 ? bw_for_1x_8bpc :
+ fp_mult(bw_for_1x_8bpc, fp_mult(ten_bpc_packing_factor,
+ ten_bpc_bpp_factor));
+
+ ddr.original_read = fp_div(fp_mult(FP(1, 50, 100), dpb_bw_for_1x),
+ input_compression_factor);
+
ddr.original_write = FP_ZERO;
- ddr.dpb_read = FP_ZERO;
+ ref_y_bw_factor =
+ width == vertical_tile_width ? FP_INT(1) : ref_y_bw_factor;
- ddr.dpb_read = fp_div(ddr.dpb_read, dpb_compression_factor);
- ddr.dpb_write = fp_div(one_frame_bw_dpb, dpb_compression_factor);
+ ref_y_read = fp_mult(ref_y_bw_factor, dpb_bw_for_1x);
+
+ ref_y_read = fp_div(ref_y_read, dpb_compression_factor);
+
+ ref_y_read =
+ b_frames_enabled ? fp_mult(ref_y_read, FP_INT(2)) : ref_y_read;
+
+ llc_ref_y_read = ref_y_read;
+ if (llc_dual_core_ref_read_buf_enabled)
+ ref_y_read = fp_div(ref_y_read, FP_INT(2));
+
+ llc_ref_y_read -= ref_y_read;
+
+ ref_cb_cr_read = fp_mult(ref_cb_cr_bw_factor, dpb_bw_for_1x);
+
+ ref_cb_cr_read = fp_div(ref_cb_cr_read, dpb_compression_factor);
+
+ ref_cb_cr_read =
+ b_frames_enabled ? fp_mult(ref_cb_cr_read, FP_INT(2)) :
+ ref_cb_cr_read;
+
+ llc_ref_cb_cr_read = ref_cb_cr_read;
+
+ if (llc_ref_chroma_cache_enabled)
+ ref_cb_cr_read = fp_div(ref_cb_cr_read, ref_cb_cr_bw_factor);
+
+ if (llc_dual_core_ref_read_buf_enabled)
+ ref_cb_cr_read = fp_div(ref_cb_cr_read, FP_INT(2));
+
+ llc_ref_cb_cr_read -= ref_cb_cr_read;
+
+ ddr.dpb_write = fp_mult(dpb_write_factor, dpb_bw_for_1x);
+
+ ddr.dpb_write = fp_mult(ddr.dpb_write, FP(1, 50, 100));
+
+ ddr.dpb_write = fp_div(ddr.dpb_write, input_compression_factor);
+
+ ref_overlap_bw_factor =
+ width <= vertical_tile_width ? FP_INT(0) : FP_INT(1);
+
+ ref_overlap_bw = fp_mult(ddr.dpb_write, ref_overlap_bw_factor);
+
+ ref_overlap_bw = fp_div(ref_overlap_bw, dpb_write_factor);
+
+ ref_overlap_bw = fp_mult(ref_overlap_bw,
+ (dpb_write_factor - FP_INT(1)));
+
+ ddr.dpb_read = ref_y_read + ref_cb_cr_read + ref_overlap_bw;
+
+ llc.dpb_read = llc_ref_y_read + llc_ref_cb_cr_read;
ddr.total = ddr.vsp_read + ddr.vsp_write +
ddr.collocated_read + ddr.collocated_write +
@@ -733,13 +786,14 @@
ddr.original_read + ddr.original_write +
ddr.dpb_read + ddr.dpb_write;
+ llc.total = llc.dpb_read + llc.line_buffer;
+
qsmmu_bw_overhead_factor = FP(1, 3, 100);
ddr.total = fp_mult(ddr.total, qsmmu_bw_overhead_factor);
if (debug) {
struct dump dump[] = {
{"ENCODER PARAMETERS", "", DUMP_HEADER_MAGIC},
- {"standard", "%#x", standard},
{"width", "%d", width},
{"height", "%d", height},
{"DPB format", "%#x", dpb_color_format},
@@ -748,8 +802,8 @@
{"DPB compression enable", "%d", dpb_compression_enabled},
{"original compression enable", "%d",
original_compression_enabled},
- {"two stage encoding", "%d", two_stage_encoding},
{"low power mode", "%d", low_power},
+ {"Work Mode", "%d", work_mode_1},
{"DPB compression factor", DUMP_FP_FMT,
dpb_compression_factor},
{"original compression factor", DUMP_FP_FMT,
@@ -759,46 +813,27 @@
{"DERIVED PARAMETERS", "", DUMP_HEADER_MAGIC},
{"LCU size", "%d", lcu_size},
- {"GOB pattern", "%d", gop},
{"bitrate (Mbit/sec)", "%lu", bitrate},
{"bins to bit factor", DUMP_FP_FMT, bins_to_bit_factor},
- {"B-frames enabled", "%d", b_frames_enabled},
- {"search window size vertical (B)", "%d",
- search_window_size_vertical_b},
- {"search window factor (B)", "%d", search_window_factor_b},
- {"search window factor BW (B)", "%d",
- search_window_factor_bw_b},
- {"bw increase (MB/s) (B)", DUMP_FP_FMT, bw_increase_b},
- {"search window size vertical (P)", "%d",
- search_window_size_vertical_p},
- {"search window factor (P)", "%d", search_window_factor_p},
- {"search window factor BW (P)", "%d",
- search_window_factor_bw_p},
- {"bw increase (MB/s) (P)", DUMP_FP_FMT, bw_increase_p},
- {"chroma/luma factor DPB", DUMP_FP_FMT,
- chroma_luma_factor_dpb},
- {"one frame BW DPB (MB/s)", DUMP_FP_FMT, one_frame_bw_dpb},
- {"chroma/Luma factor original", DUMP_FP_FMT,
- chroma_luma_factor_original},
- {"one frame BW original (MB/s)", DUMP_FP_FMT,
- one_frame_bw_original},
- {"line buffer size per LCU", DUMP_FP_FMT,
- line_buffer_size_per_lcu},
- {"line buffer size (KB)", DUMP_FP_FMT, line_buffer_size},
- {"line buffer BW (MB/s)", DUMP_FP_FMT, line_buffer_bw},
- {"collocated MVs per LCU", "%d", collocated_mv_per_lcu},
+ {"qsmmu_bw_overhead_factor",
+ DUMP_FP_FMT, qsmmu_bw_overhead_factor},
{"INTERMEDIATE B/W DDR", "", DUMP_HEADER_MAGIC},
+ {"ref_y_read", DUMP_FP_FMT, ref_y_read},
+ {"ref_cb_cr_read", DUMP_FP_FMT, ref_cb_cr_read},
+ {"ref_overlap_bw", DUMP_FP_FMT, ref_overlap_bw},
{"VSP read", DUMP_FP_FMT, ddr.vsp_read},
- {"VSP read", DUMP_FP_FMT, ddr.vsp_write},
+ {"VSP write", DUMP_FP_FMT, ddr.vsp_write},
{"collocated read", DUMP_FP_FMT, ddr.collocated_read},
- {"collocated read", DUMP_FP_FMT, ddr.collocated_write},
+ {"collocated write", DUMP_FP_FMT, ddr.collocated_write},
{"line buffer read", DUMP_FP_FMT, ddr.line_buffer_read},
- {"line buffer read", DUMP_FP_FMT, ddr.line_buffer_write},
+ {"line buffer write", DUMP_FP_FMT, ddr.line_buffer_write},
{"original read", DUMP_FP_FMT, ddr.original_read},
- {"original read", DUMP_FP_FMT, ddr.original_write},
+ {"original write", DUMP_FP_FMT, ddr.original_write},
{"DPB read", DUMP_FP_FMT, ddr.dpb_read},
{"DPB write", DUMP_FP_FMT, ddr.dpb_write},
+ {"LLC DPB read", DUMP_FP_FMT, llc.dpb_read},
+ {"LLC Line buffer", DUMP_FP_FMT, llc.line_buffer},
};
__dump(dump, ARRAY_SIZE(dump));
}
@@ -808,7 +843,7 @@
ret = kbps(fp_round(ddr.total));
break;
case GOVERNOR_LLCC:
- dprintk(VIDC_PROF, "LLCC Voting not supported yet\n");
+ ret = kbps(fp_round(llc.total));
break;
default:
dprintk(VIDC_ERR, "%s - Unknown governor\n", __func__);
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index e5d1576..a08f282 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -1140,6 +1140,12 @@
buffreq->buffer[10].buffer_type =
HAL_BUFFER_INTERNAL_PERSIST_1;
break;
+ case HFI_BUFFER_COMMON_INTERNAL_RECON:
+ memcpy(&buffreq->buffer[11], hfi_buf_req,
+ sizeof(struct hfi_buffer_requirements));
+ buffreq->buffer[11].buffer_type =
+ HAL_BUFFER_INTERNAL_RECON;
+ break;
default:
dprintk(VIDC_ERR,
"hal_process_sess_get_prop_buf_req: bad_buffer_type: %d\n",
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index bc4b280..69070d5 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -1599,7 +1599,7 @@
break;
case V4L2_CID_MPEG_VIDC_VIDEO_USELTRFRAME:
property_id = HAL_CONFIG_VENC_USELTRFRAME;
- use_ltr.ref_ltr = ctrl->val;
+ use_ltr.ref_ltr = 0x1 << ctrl->val;
use_ltr.use_constraint = false;
use_ltr.frames = 0;
pdata = &use_ltr;
@@ -2362,6 +2362,7 @@
rc = -EINVAL;
goto exit;
}
+ inst->clk_data.opb_fourcc = f->fmt.pix_mp.pixelformat;
memcpy(&inst->fmts[fmt->type], fmt,
sizeof(struct msm_vidc_format));
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 1b931ee..854aa0a 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -442,6 +442,7 @@
struct msm_vidc_inst *inst = instance;
int rc = 0, i = 0;
struct buf_queue *q = NULL;
+ u32 cr = 0;
if (!inst || !inst->core || !b || !valid_v4l2_buffer(b, inst)) {
dprintk(VIDC_ERR, "%s: invalid params, inst %pK\n",
@@ -453,8 +454,16 @@
b->m.planes[i].m.fd = b->m.planes[i].reserved[0];
b->m.planes[i].data_offset = b->m.planes[i].reserved[1];
}
+
msm_comm_qbuf_cache_operations(inst, b);
+ /* Compression ratio is valid only for Encoder YUV buffers. */
+ if (inst->session_type == MSM_VIDC_ENCODER &&
+ b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ cr = b->m.planes[0].reserved[2];
+ msm_comm_update_input_cr(inst, b->index, cr);
+ }
+
q = msm_comm_get_vb2q(inst, b->type);
if (!q) {
dprintk(VIDC_ERR,
@@ -712,7 +721,6 @@
rc = set_buffer_count(inst, bufreq->buffer_count_min_host,
bufreq->buffer_count_actual, HAL_BUFFER_INPUT);
}
-
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: {
buffer_type = msm_comm_get_hal_output_buffer(inst);
@@ -1494,6 +1502,7 @@
INIT_MSM_VIDC_LIST(&inst->scratchbufs);
INIT_MSM_VIDC_LIST(&inst->freqs);
+ INIT_MSM_VIDC_LIST(&inst->input_crs);
INIT_MSM_VIDC_LIST(&inst->persistbufs);
INIT_MSM_VIDC_LIST(&inst->pending_getpropq);
INIT_MSM_VIDC_LIST(&inst->outputbufs);
@@ -1605,6 +1614,8 @@
DEINIT_MSM_VIDC_LIST(&inst->outputbufs);
DEINIT_MSM_VIDC_LIST(&inst->registeredbufs);
DEINIT_MSM_VIDC_LIST(&inst->eosbufs);
+ DEINIT_MSM_VIDC_LIST(&inst->freqs);
+ DEINIT_MSM_VIDC_LIST(&inst->input_crs);
kfree(inst);
inst = NULL;
@@ -1634,6 +1645,8 @@
msm_comm_free_freq_table(inst);
+ msm_comm_free_input_cr_table(inst);
+
if (msm_comm_release_scratch_buffers(inst, false))
dprintk(VIDC_ERR,
"Failed to release scratch buffers\n");
@@ -1699,6 +1712,8 @@
DEINIT_MSM_VIDC_LIST(&inst->outputbufs);
DEINIT_MSM_VIDC_LIST(&inst->registeredbufs);
DEINIT_MSM_VIDC_LIST(&inst->eosbufs);
+ DEINIT_MSM_VIDC_LIST(&inst->freqs);
+ DEINIT_MSM_VIDC_LIST(&inst->input_crs);
mutex_destroy(&inst->sync_lock);
mutex_destroy(&inst->bufq[CAPTURE_PORT].lock);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
index 6b09a54..8074c05 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
@@ -19,6 +19,9 @@
#define MSM_VIDC_MIN_UBWC_COMPLEXITY_FACTOR (1 << 16)
#define MSM_VIDC_MAX_UBWC_COMPLEXITY_FACTOR (4 << 16)
+#define MSM_VIDC_MIN_UBWC_COMPRESSION_RATIO (1 << 16)
+#define MSM_VIDC_MAX_UBWC_COMPRESSION_RATIO (5 << 16)
+
static inline unsigned long int get_ubwc_compression_ratio(
struct ubwc_cr_stats_info_type ubwc_stats_info)
{
@@ -90,36 +93,56 @@
mutex_unlock(&inst->reconbufs.lock);
}
-static int fill_recon_stats(struct msm_vidc_inst *inst,
+static int fill_dynamic_stats(struct msm_vidc_inst *inst,
struct vidc_bus_vote_data *vote_data)
{
- struct recon_buf *binfo;
- u32 CR = 0, min_cf = MSM_VIDC_MIN_UBWC_COMPLEXITY_FACTOR,
- max_cf = MSM_VIDC_MAX_UBWC_COMPLEXITY_FACTOR;
+ struct recon_buf *binfo, *nextb;
+ struct vidc_input_cr_data *temp, *next;
+ u32 min_cf = 0, max_cf = 0;
+ u32 min_input_cr = 0, max_input_cr = 0, min_cr = 0, max_cr = 0;
mutex_lock(&inst->reconbufs.lock);
- list_for_each_entry(binfo, &inst->reconbufs.list, list) {
- CR = max(CR, binfo->CR);
+ list_for_each_entry_safe(binfo, nextb, &inst->reconbufs.list, list) {
+ min_cr = min(min_cr, binfo->CR);
+ max_cr = max(max_cr, binfo->CR);
min_cf = min(min_cf, binfo->CF);
max_cf = max(max_cf, binfo->CF);
}
mutex_unlock(&inst->reconbufs.lock);
+ mutex_lock(&inst->input_crs.lock);
+ list_for_each_entry_safe(temp, next, &inst->input_crs.list, list) {
+ min_input_cr = min(min_input_cr, temp->input_cr);
+ max_input_cr = max(max_input_cr, temp->input_cr);
+ }
+ mutex_unlock(&inst->input_crs.lock);
+
/* Sanitize CF values from HW . */
max_cf = min_t(u32, max_cf, MSM_VIDC_MAX_UBWC_COMPLEXITY_FACTOR);
min_cf = max_t(u32, min_cf, MSM_VIDC_MIN_UBWC_COMPLEXITY_FACTOR);
+ max_cr = min_t(u32, max_cr, MSM_VIDC_MAX_UBWC_COMPRESSION_RATIO);
+ min_cr = max_t(u32, min_cr, MSM_VIDC_MIN_UBWC_COMPRESSION_RATIO);
+ max_input_cr = min_t(u32,
+ max_input_cr, MSM_VIDC_MAX_UBWC_COMPRESSION_RATIO);
+ min_input_cr = max_t(u32,
+ min_input_cr, MSM_VIDC_MIN_UBWC_COMPRESSION_RATIO);
- vote_data->compression_ratio = CR;
+ vote_data->compression_ratio = min_cr;
vote_data->complexity_factor = max_cf;
+ vote_data->input_cr = min_input_cr;
vote_data->use_dpb_read = false;
+
+ /* Check if driver can vote for lower bus BW */
if (inst->clk_data.load <= inst->clk_data.load_norm) {
+ vote_data->compression_ratio = max_cr;
vote_data->complexity_factor = min_cf;
+ vote_data->input_cr = max_input_cr;
vote_data->use_dpb_read = true;
}
- dprintk(VIDC_DBG,
- "Compression Ratio = %d Complexity Factor = %d\n",
- vote_data->compression_ratio,
+ dprintk(VIDC_PROF,
+ "Input CR = %d Recon CR = %d Complexity Factor = %d\n",
+ vote_data->input_cr, vote_data->compression_ratio,
vote_data->complexity_factor);
return 0;
@@ -186,6 +209,8 @@
inst->fmts[OUTPUT_PORT].fourcc :
inst->fmts[CAPTURE_PORT].fourcc;
+ memset(&(vote_data[i]), 0x0, sizeof(struct vidc_bus_vote_data));
+
vote_data[i].domain = get_hal_domain(inst->session_type);
vote_data[i].codec = get_hal_codec(codec);
vote_data[i].input_width = max(inst->prop.width[OUTPUT_PORT],
@@ -198,6 +223,9 @@
max(inst->prop.height[CAPTURE_PORT],
inst->prop.height[OUTPUT_PORT]);
vote_data[i].lcu_size = codec == V4L2_PIX_FMT_HEVC ? 32 : 16;
+ vote_data[i].b_frames_enabled =
+ msm_comm_g_ctrl_for_id(inst,
+ V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES) != 0;
if (inst->clk_data.operating_rate)
vote_data[i].fps =
@@ -227,7 +255,7 @@
vote_data[i].num_formats = 2;
}
vote_data[i].work_mode = inst->clk_data.work_mode;
- fill_recon_stats(inst, &vote_data[i]);
+ fill_dynamic_stats(inst, &vote_data[i]);
if (core->resources.sys_cache_res_set)
vote_data[i].use_sys_cache = true;
@@ -356,10 +384,15 @@
if (!found) {
temp = kzalloc(sizeof(*temp), GFP_KERNEL);
+ if (!temp) {
+ dprintk(VIDC_WARN, "%s: malloc failure.\n", __func__);
+ goto exit;
+ }
temp->freq = freq;
temp->device_addr = device_addr;
list_add_tail(&temp->list, &inst->freqs.list);
}
+exit:
mutex_unlock(&inst->freqs.lock);
}
@@ -415,6 +448,48 @@
mutex_unlock(&inst->freqs.lock);
}
+void msm_comm_free_input_cr_table(struct msm_vidc_inst *inst)
+{
+ struct vidc_input_cr_data *temp, *next;
+
+ mutex_lock(&inst->input_crs.lock);
+ list_for_each_entry_safe(temp, next, &inst->input_crs.list, list) {
+ list_del(&temp->list);
+ kfree(temp);
+ }
+ INIT_LIST_HEAD(&inst->input_crs.list);
+ mutex_unlock(&inst->input_crs.lock);
+}
+
+void msm_comm_update_input_cr(struct msm_vidc_inst *inst,
+ u32 index, u32 cr)
+{
+ struct vidc_input_cr_data *temp, *next;
+ bool found = false;
+
+ mutex_lock(&inst->input_crs.lock);
+ list_for_each_entry_safe(temp, next, &inst->input_crs.list, list) {
+ if (temp->index == index) {
+ temp->input_cr = cr;
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ temp = kzalloc(sizeof(*temp), GFP_KERNEL);
+ if (!temp) {
+ dprintk(VIDC_WARN, "%s: malloc failure.\n", __func__);
+ goto exit;
+ }
+ temp->index = index;
+ temp->input_cr = cr;
+ list_add_tail(&temp->list, &inst->input_crs.list);
+ }
+exit:
+ mutex_unlock(&inst->input_crs.lock);
+}
+
static unsigned long msm_vidc_max_freq(struct msm_vidc_core *core)
{
struct allowed_clock_rates_table *allowed_clks_tbl = NULL;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.h b/drivers/media/platform/msm/vidc/msm_vidc_clocks.h
index 705cb7c..707f034 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.h
@@ -33,6 +33,9 @@
int msm_vidc_decide_core_and_power_mode(struct msm_vidc_inst *inst);
void msm_vidc_clear_freq_entry(struct msm_vidc_inst *inst,
u32 device_addr);
+void msm_comm_free_input_cr_table(struct msm_vidc_inst *inst);
+void msm_comm_update_input_cr(struct msm_vidc_inst *inst, u32 index,
+ u32 cr);
void update_recon_stats(struct msm_vidc_inst *inst,
struct recon_stats_type *recon_stats);
#endif
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 48afa0b..1b8e438 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -79,7 +79,6 @@
static void msm_comm_generate_sys_error(struct msm_vidc_inst *inst);
static void handle_session_error(enum hal_command_response cmd, void *data);
static void msm_vidc_print_running_insts(struct msm_vidc_core *core);
-static void msm_comm_print_debug_info(struct msm_vidc_inst *inst);
bool msm_comm_turbo_session(struct msm_vidc_inst *inst)
{
@@ -2708,8 +2707,6 @@
int msm_comm_check_core_init(struct msm_vidc_core *core)
{
int rc = 0;
- struct hfi_device *hdev;
- struct msm_vidc_inst *inst = NULL;
mutex_lock(&core->lock);
if (core->state >= VIDC_CORE_INIT_DONE) {
@@ -2718,29 +2715,12 @@
goto exit;
}
dprintk(VIDC_DBG, "Waiting for SYS_INIT_DONE\n");
- hdev = (struct hfi_device *)core->device;
rc = wait_for_completion_timeout(
&core->completions[SYS_MSG_INDEX(HAL_SYS_INIT_DONE)],
msecs_to_jiffies(core->resources.msm_vidc_hw_rsp_timeout));
if (!rc) {
dprintk(VIDC_ERR, "%s: Wait interrupted or timed out: %d\n",
__func__, SYS_MSG_INDEX(HAL_SYS_INIT_DONE));
- call_hfi_op(hdev, flush_debug_queue, hdev->hfi_device_data);
- dprintk(VIDC_ERR,
- "SYS_INIT timeout can potentially crash the system\n");
- /*
- * For SYS_INIT, there will not be any inst pointer.
- * Just grab one of the inst from instances list and
- * use it.
- */
- inst = list_first_entry(&core->instances,
- struct msm_vidc_inst, list);
-
- mutex_unlock(&core->lock);
- msm_comm_print_debug_info(inst);
- mutex_lock(&core->lock);
-
- msm_vidc_handle_hw_error(core);
rc = -EIO;
goto exit;
} else {
@@ -4769,8 +4749,7 @@
return 0;
}
- if (!list_empty(&inst->reconbufs.list))
- msm_comm_release_recon_buffers(inst);
+ msm_comm_release_recon_buffers(inst);
for (i = 0; i < internal_buf->buffer_count_actual; i++) {
binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
@@ -5692,32 +5671,6 @@
mutex_unlock(&inst->outputbufs.lock);
}
-static void msm_comm_print_debug_info(struct msm_vidc_inst *inst)
-{
- struct msm_vidc_core *core = NULL;
- struct msm_vidc_inst *temp = NULL;
-
- if (!inst || !inst->core) {
- dprintk(VIDC_ERR, "%s - invalid param %pK %pK\n",
- __func__, inst, core);
- return;
- }
- core = inst->core;
-
- dprintk(VIDC_ERR, "Venus core frequency = %lu", core->curr_freq);
- mutex_lock(&core->lock);
- dprintk(VIDC_ERR, "Printing instance info that caused Error\n");
- msm_comm_print_inst_info(inst);
- dprintk(VIDC_ERR, "Printing remaining instances info\n");
- list_for_each_entry(temp, &core->instances, list) {
- /* inst already printed above. Hence don't repeat.*/
- if (temp == inst)
- continue;
- msm_comm_print_inst_info(temp);
- }
- mutex_unlock(&core->lock);
-}
-
int msm_comm_session_continue(void *instance)
{
struct msm_vidc_inst *inst = instance;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index 6511029..57dfd52 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -144,6 +144,12 @@
unsigned long freq;
};
+struct vidc_input_cr_data {
+ struct list_head list;
+ u32 index;
+ u32 input_cr;
+};
+
struct recon_buf {
struct list_head list;
u32 buffer_index;
@@ -327,6 +333,7 @@
struct msm_vidc_format fmts[MAX_PORT_NUM];
struct buf_queue bufq[MAX_PORT_NUM];
struct msm_vidc_list freqs;
+ struct msm_vidc_list input_crs;
struct msm_vidc_list scratchbufs;
struct msm_vidc_list persistbufs;
struct msm_vidc_list pending_getpropq;
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 15246d3..8064f4c 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -2803,6 +2803,8 @@
}
}
+ __flush_debug_queue(device, device->raw_packet);
+
rc = __suspend(device);
if (rc)
dprintk(VIDC_ERR, "Failed __suspend\n");
@@ -3404,6 +3406,15 @@
.exit = NULL,
};
+ if (!strcmp(bus->governor, "msm-vidc-llcc")) {
+ if (msm_vidc_syscache_disable) {
+ dprintk(VIDC_DBG,
+ "Skipping LLC bus init %s: %s\n",
+ bus->name, bus->governor);
+ continue;
+ }
+ }
+
/*
* This is stupid, but there's no other easy way to ahold
* of struct bus_info in venus_hfi_devfreq_*()
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index fbd3b02..e854b43 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -1345,11 +1345,13 @@
int output_height, output_width;
int compression_ratio;
int complexity_factor;
+ int input_cr;
bool use_dpb_read;
unsigned int lcu_size;
enum msm_vidc_power_mode power_mode;
enum hal_work_mode work_mode;
bool use_sys_cache;
+ bool b_frames_enabled;
};
struct vidc_clk_scale_data {
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index e203ba6..2e5da54 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -479,6 +479,15 @@
the genalloc API. It is supposed to be used for small on-chip SRAM
areas found on many SoCs.
+config HDCP_QSEECOM
+ tristate "QTI High-Bandwidth Digital Content Protection Module"
+ help
+ This module implements HDCP 2.2 features over external interfaces
+ such as the DisplayPort interface. It exposes APIs for the interface
+ driver to communicate with QTI Secure Execution Environment (QSEE)
+ via the QSEECOM Driver and also communicates with the Receiver via
+ APIs exposed by the interface driver.
+
config QSEECOM
tristate "QTI Secure Execution Communicator driver"
help
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index e1c6ae1..cfea4a5 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -49,6 +49,7 @@
obj-$(CONFIG_SRAM) += sram.o
obj-y += mic/
obj-$(CONFIG_GENWQE) += genwqe/
+obj-$(CONFIG_HDCP_QSEECOM) += hdcp.o
obj-$(CONFIG_QSEECOM) += qseecom.o
obj-$(CONFIG_ECHO) += echo/
obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o
diff --git a/drivers/misc/hdcp.c b/drivers/misc/hdcp.c
new file mode 100644
index 0000000..eab93cc
--- /dev/null
+++ b/drivers/misc/hdcp.c
@@ -0,0 +1,2549 @@
+/* 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "[hdcp-lib] %s: " fmt, __func__
+
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/uaccess.h>
+#include <linux/cdev.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+#include <linux/ion.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <linux/errno.h>
+#include <linux/hdcp_qseecom.h>
+#include <linux/kthread.h>
+#include <linux/of.h>
+#include <video/msm_hdmi_hdcp_mgr.h>
+
+#include "qseecom_kernel.h"
+
+#define CLASS_NAME "hdcp"
+#define DRIVER_NAME "msm_hdcp"
+#define TZAPP_NAME "hdcp2p2"
+#define HDCP1_APP_NAME "hdcp1"
+#define QSEECOM_SBUFF_SIZE 0x1000
+
+#define MAX_TX_MESSAGE_SIZE 129
+#define MAX_RX_MESSAGE_SIZE 534
+#define MAX_TOPOLOGY_ELEMS 32
+#define HDCP1_AKSV_SIZE 8
+
+/* parameters related to LC_Init message */
+#define MESSAGE_ID_SIZE 1
+#define LC_INIT_MESSAGE_SIZE (MESSAGE_ID_SIZE+BITS_64_IN_BYTES)
+
+/* parameters related to SKE_Send_EKS message */
+#define SKE_SEND_EKS_MESSAGE_SIZE \
+ (MESSAGE_ID_SIZE+BITS_128_IN_BYTES+BITS_64_IN_BYTES)
+
+/* all message IDs */
+#define INVALID_MESSAGE_ID 0
+#define AKE_INIT_MESSAGE_ID 2
+#define AKE_SEND_CERT_MESSAGE_ID 3
+#define AKE_NO_STORED_KM_MESSAGE_ID 4
+#define AKE_STORED_KM_MESSAGE_ID 5
+#define AKE_SEND_H_PRIME_MESSAGE_ID 7
+#define AKE_SEND_PAIRING_INFO_MESSAGE_ID 8
+#define LC_INIT_MESSAGE_ID 9
+#define LC_SEND_L_PRIME_MESSAGE_ID 10
+#define SKE_SEND_EKS_MESSAGE_ID 11
+#define REPEATER_AUTH_SEND_RECEIVERID_LIST_MESSAGE_ID 12
+#define REPEATER_AUTH_SEND_ACK_MESSAGE_ID 15
+#define REPEATER_AUTH_STREAM_MANAGE_MESSAGE_ID 16
+#define REPEATER_AUTH_STREAM_READY_MESSAGE_ID 17
+#define SKE_SEND_TYPE_ID 18
+#define HDCP2P2_MAX_MESSAGES 19
+
+#define HDCP1_SET_KEY_MESSAGE_ID 202
+#define HDCP1_SET_ENC_MESSAGE_ID 205
+
+#define BITS_40_IN_BYTES 5
+#define BITS_64_IN_BYTES 8
+#define BITS_128_IN_BYTES 16
+#define RXCAPS_SIZE 3
+#define RXINFO_SIZE 2
+#define SEQ_NUM_V_SIZE 3
+
+#define RCVR_ID_SIZE BITS_40_IN_BYTES
+#define MAX_RCVR_IDS_ALLOWED_IN_LIST 31
+#define MAX_RCVR_ID_LIST_SIZE \
+ (RCVR_ID_SIZE * MAX_RCVR_IDS_ALLOWED_IN_LIST)
+/*
+ * Minimum wait as per standard is 200 ms. Keep it 220 ms
+ * to be on safe side.
+ */
+#define SLEEP_SET_HW_KEY_MS 220
+
+/* hdcp command status */
+#define HDCP_SUCCESS 0
+
+/* flags set by tz in response message */
+#define HDCP_TXMTR_SUBSTATE_WAITING_FOR_RECIEVERID_LIST 1
+
+#define HDCP_TXMTR_SERVICE_ID 0x0001000
+#define SERVICE_CREATE_CMD(x) (HDCP_TXMTR_SERVICE_ID | x)
+
+#define HDCP_TXMTR_INIT SERVICE_CREATE_CMD(1)
+#define HDCP_TXMTR_DEINIT SERVICE_CREATE_CMD(2)
+#define HDCP_TXMTR_PROCESS_RECEIVED_MESSAGE SERVICE_CREATE_CMD(3)
+#define HDCP_TXMTR_SEND_MESSAGE_TIMEOUT SERVICE_CREATE_CMD(4)
+#define HDCP_TXMTR_SET_HW_KEY SERVICE_CREATE_CMD(5)
+#define HDCP_TXMTR_QUERY_STREAM_TYPE SERVICE_CREATE_CMD(6)
+#define HDCP_LIB_INIT SERVICE_CREATE_CMD(11)
+#define HDCP_LIB_DEINIT SERVICE_CREATE_CMD(12)
+#define HDCP_TXMTR_GET_VERSION SERVICE_CREATE_CMD(14)
+#define HDCP_TXMTR_VERIFY_KEY SERVICE_CREATE_CMD(15)
+#define HDCP_SESSION_INIT SERVICE_CREATE_CMD(16)
+#define HDCP_SESSION_DEINIT SERVICE_CREATE_CMD(17)
+#define HDCP_TXMTR_START_AUTHENTICATE SERVICE_CREATE_CMD(18)
+
+#define HCDP_TXMTR_GET_MAJOR_VERSION(v) (((v) >> 16) & 0xFF)
+#define HCDP_TXMTR_GET_MINOR_VERSION(v) (((v) >> 8) & 0xFF)
+#define HCDP_TXMTR_GET_PATCH_VERSION(v) ((v) & 0xFF)
+
+#define HDCP_CLIENT_MAJOR_VERSION 2
+#define HDCP_CLIENT_MINOR_VERSION 1
+#define HDCP_CLIENT_PATCH_VERSION 0
+#define HDCP_CLIENT_MAKE_VERSION(maj, min, patch) \
+ ((((maj) & 0xFF) << 16) | (((min) & 0xFF) << 8) | ((patch) & 0xFF))
+
+#define REAUTH_REQ BIT(3)
+#define LINK_INTEGRITY_FAILURE BIT(4)
+
+#define HDCP_LIB_EXECUTE(x) {\
+ kthread_queue_work(&handle->worker, &handle->wk_##x);\
+}
+
+static const struct hdcp_msg_data hdcp_msg_lookup[HDCP2P2_MAX_MESSAGES] = {
+ [AKE_INIT_MESSAGE_ID] = { 2,
+ { {"rtx", 0x69000, 8}, {"TxCaps", 0x69008, 3} },
+ 0 },
+ [AKE_SEND_CERT_MESSAGE_ID] = { 3,
+ { {"cert-rx", 0x6900B, 522}, {"rrx", 0x69215, 8},
+ {"RxCaps", 0x6921D, 3} },
+ 0 },
+ [AKE_NO_STORED_KM_MESSAGE_ID] = { 1,
+ { {"Ekpub_km", 0x69220, 128} },
+ 0 },
+ [AKE_STORED_KM_MESSAGE_ID] = { 2,
+ { {"Ekh_km", 0x692A0, 16}, {"m", 0x692B0, 16} },
+ 0 },
+ [AKE_SEND_H_PRIME_MESSAGE_ID] = { 1,
+ { {"H'", 0x692C0, 32} },
+ (1 << 1) },
+ [AKE_SEND_PAIRING_INFO_MESSAGE_ID] = { 1,
+ { {"Ekh_km", 0x692E0, 16} },
+ (1 << 2) },
+ [LC_INIT_MESSAGE_ID] = { 1,
+ { {"rn", 0x692F0, 8} },
+ 0 },
+ [LC_SEND_L_PRIME_MESSAGE_ID] = { 1,
+ { {"L'", 0x692F8, 32} },
+ 0 },
+ [SKE_SEND_EKS_MESSAGE_ID] = { 2,
+ { {"Edkey_ks", 0x69318, 16}, {"riv", 0x69328, 8} },
+ 0 },
+ [SKE_SEND_TYPE_ID] = { 1,
+ { {"type", 0x69494, 1} },
+ 0 },
+ [REPEATER_AUTH_SEND_RECEIVERID_LIST_MESSAGE_ID] = { 4,
+ { {"RxInfo", 0x69330, 2}, {"seq_num_V", 0x69332, 3},
+ {"V'", 0x69335, 16}, {"ridlist", 0x69345, 155} },
+ (1 << 0) },
+ [REPEATER_AUTH_SEND_ACK_MESSAGE_ID] = { 1,
+ { {"V", 0x693E0, 16} },
+ 0 },
+ [REPEATER_AUTH_STREAM_MANAGE_MESSAGE_ID] = { 3,
+ { {"seq_num_M", 0x693F0, 3}, {"k", 0x693F3, 2},
+ {"streamID_Type", 0x693F5, 126} },
+ 0 },
+ [REPEATER_AUTH_STREAM_READY_MESSAGE_ID] = { 1,
+ { {"M'", 0x69473, 32} },
+ 0 }
+};
+
+enum hdcp_state {
+ HDCP_STATE_INIT = 0x00,
+ HDCP_STATE_APP_LOADED = 0x01,
+ HDCP_STATE_SESSION_INIT = 0x02,
+ HDCP_STATE_TXMTR_INIT = 0x04,
+ HDCP_STATE_AUTHENTICATED = 0x08,
+ HDCP_STATE_ERROR = 0x10
+};
+
+enum hdcp_element {
+ HDCP_TYPE_UNKNOWN,
+ HDCP_TYPE_RECEIVER,
+ HDCP_TYPE_REPEATER,
+};
+
+enum hdcp_version {
+ HDCP_VERSION_UNKNOWN,
+ HDCP_VERSION_2_2,
+ HDCP_VERSION_1_4
+};
+
+struct receiver_info {
+ unsigned char rcvrInfo[RCVR_ID_SIZE];
+ enum hdcp_element elem_type;
+ enum hdcp_version hdcp_version;
+};
+
+struct topology_info {
+ unsigned int nNumRcvrs;
+ struct receiver_info rcvinfo[MAX_TOPOLOGY_ELEMS];
+};
+
+struct __attribute__ ((__packed__)) hdcp1_key_set_req {
+ uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp1_key_set_rsp {
+ uint32_t commandid;
+ uint32_t ret;
+ uint8_t ksv[HDCP1_AKSV_SIZE];
+};
+
+struct __attribute__ ((__packed__)) hdcp_version_req {
+ uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_version_rsp {
+ uint32_t commandid;
+ uint32_t commandId;
+ uint32_t appversion;
+};
+
+struct __attribute__ ((__packed__)) hdcp_verify_key_req {
+ uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_verify_key_rsp {
+ uint32_t status;
+ uint32_t commandId;
+};
+
+struct __attribute__ ((__packed__)) hdcp_lib_init_req_v1 {
+ uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_lib_init_rsp_v1 {
+ uint32_t status;
+ uint32_t commandid;
+ uint32_t ctxhandle;
+ uint32_t timeout;
+ uint32_t msglen;
+ uint8_t message[MAX_TX_MESSAGE_SIZE];
+};
+
+struct __attribute__ ((__packed__)) hdcp_lib_init_req {
+ uint32_t commandid;
+ uint32_t clientversion;
+};
+
+struct __attribute__ ((__packed__)) hdcp_lib_init_rsp {
+ uint32_t status;
+ uint32_t commandid;
+ uint32_t appversion;
+};
+
+struct __attribute__ ((__packed__)) hdcp_lib_deinit_req {
+ uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_lib_deinit_rsp {
+ uint32_t status;
+ uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_lib_session_init_req {
+ uint32_t commandid;
+ uint32_t deviceid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_lib_session_init_rsp {
+ uint32_t status;
+ uint32_t commandid;
+ uint32_t sessionid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_lib_session_deinit_req {
+ uint32_t commandid;
+ uint32_t sessionid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_lib_session_deinit_rsp {
+ uint32_t status;
+ uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_tx_init_req_v1 {
+ uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_tx_init_rsp_v1 {
+ uint32_t status;
+ uint32_t commandid;
+ uint32_t ctxhandle;
+ uint32_t timeout;
+ uint32_t msglen;
+ uint8_t message[MAX_TX_MESSAGE_SIZE];
+};
+
+struct __attribute__ ((__packed__)) hdcp_tx_init_req {
+ uint32_t commandid;
+ uint32_t sessionid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_tx_init_rsp {
+ uint32_t status;
+ uint32_t commandid;
+ uint32_t ctxhandle;
+};
+
+struct __attribute__ ((__packed__)) hdcp_deinit_req {
+ uint32_t commandid;
+ uint32_t ctxhandle;
+};
+
+struct __attribute__ ((__packed__)) hdcp_deinit_rsp {
+ uint32_t status;
+ uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_rcvd_msg_req {
+ uint32_t commandid;
+ uint32_t ctxhandle;
+ uint32_t msglen;
+ uint8_t msg[MAX_RX_MESSAGE_SIZE];
+};
+
+struct __attribute__ ((__packed__)) hdcp_rcvd_msg_rsp {
+ uint32_t status;
+ uint32_t commandid;
+ uint32_t state;
+ uint32_t timeout;
+ uint32_t flag;
+ uint32_t msglen;
+ uint8_t msg[MAX_TX_MESSAGE_SIZE];
+};
+
+struct __attribute__ ((__packed__)) hdcp_set_hw_key_req {
+ uint32_t commandid;
+ uint32_t ctxhandle;
+};
+
+struct __attribute__ ((__packed__)) hdcp_set_hw_key_rsp {
+ uint32_t status;
+ uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_send_timeout_req {
+ uint32_t commandid;
+ uint32_t ctxhandle;
+};
+
+struct __attribute__ ((__packed__)) hdcp_send_timeout_rsp {
+ uint32_t status;
+ uint32_t commandid;
+ uint32_t timeout;
+ uint32_t msglen;
+ uint8_t message[MAX_TX_MESSAGE_SIZE];
+};
+
+struct __attribute__ ((__packed__)) hdcp_query_stream_type_req {
+ uint32_t commandid;
+ uint32_t ctxhandle;
+};
+
+struct __attribute__ ((__packed__)) hdcp_query_stream_type_rsp {
+ uint32_t status;
+ uint32_t commandid;
+ uint32_t timeout;
+ uint32_t msglen;
+ uint8_t msg[MAX_TX_MESSAGE_SIZE];
+};
+
+struct __attribute__ ((__packed__)) hdcp_set_stream_type_req {
+ uint32_t commandid;
+ uint32_t ctxhandle;
+ uint8_t streamtype;
+};
+
+struct __attribute__ ((__packed__)) hdcp_set_stream_type_rsp {
+ uint32_t status;
+ uint32_t commandid;
+ uint32_t timeout;
+ uint32_t msglen;
+ uint8_t message[MAX_TX_MESSAGE_SIZE];
+};
+
+struct __attribute__ ((__packed__)) hdcp_update_srm_req {
+ uint32_t commandid;
+ uint32_t ctxhandle;
+ uint32_t srmoffset;
+ uint32_t srmlength;
+};
+
+struct __attribute__ ((__packed__)) hdcp_update_srm_rsp {
+ uint32_t status;
+ uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_get_topology_req {
+ uint32_t commandid;
+ uint32_t ctxhandle;
+};
+
+struct __attribute__ ((__packed__)) hdcp_get_topology_rsp {
+ uint32_t status;
+ uint32_t commandid;
+ struct topology_info topologyinfo;
+};
+
+struct __attribute__ ((__packed__)) rxvr_info_struct {
+ uint8_t rcvrCert[522];
+ uint8_t rrx[BITS_64_IN_BYTES];
+ uint8_t rxcaps[RXCAPS_SIZE];
+ bool repeater;
+};
+
+struct __attribute__ ((__packed__)) repeater_info_struct {
+ uint8_t RxInfo[RXINFO_SIZE];
+ uint8_t seq_num_V[SEQ_NUM_V_SIZE];
+ bool seq_num_V_Rollover_flag;
+ uint8_t ReceiverIDList[MAX_RCVR_ID_LIST_SIZE];
+ uint32_t ReceiverIDListLen;
+};
+
+struct __attribute__ ((__packed__)) hdcp1_set_enc_req {
+ uint32_t commandid;
+ uint32_t enable;
+};
+
+struct __attribute__ ((__packed__)) hdcp1_set_enc_rsp {
+ uint32_t commandid;
+ uint32_t ret;
+};
+
+struct __attribute__ ((__packed__)) hdcp_start_auth_req {
+ uint32_t commandid;
+ uint32_t ctxHandle;
+};
+
+struct __attribute__ ((__packed__)) hdcp_start_auth_rsp {
+ uint32_t status;
+ uint32_t commandid;
+ uint32_t ctxhandle;
+ uint32_t timeout;
+ uint32_t msglen;
+ uint8_t message[MAX_TX_MESSAGE_SIZE];
+};
+
+struct hdcp_lib_handle {
+ unsigned char *listener_buf;
+ uint32_t msglen;
+ uint32_t tz_ctxhandle;
+ uint32_t hdcp_timeout;
+ uint32_t timeout_left;
+ uint32_t wait_timeout;
+ bool no_stored_km_flag;
+ bool feature_supported;
+ bool authenticated;
+ void *client_ctx;
+ struct hdcp_client_ops *client_ops;
+ struct mutex msg_lock;
+ struct mutex wakeup_mutex;
+ enum hdcp_state hdcp_state;
+ enum hdcp_lib_wakeup_cmd wakeup_cmd;
+ bool repeater_flag;
+ bool update_stream;
+ struct qseecom_handle *qseecom_handle;
+ int last_msg_sent;
+ int last_msg;
+ char *last_msg_recvd_buf;
+ uint32_t last_msg_recvd_len;
+ atomic_t hdcp_off;
+ uint32_t session_id;
+ enum hdcp_device_type device_type;
+
+ struct task_struct *thread;
+ struct completion poll_wait;
+
+ struct kthread_worker worker;
+ struct kthread_work wk_init;
+ struct kthread_work wk_msg_sent;
+ struct kthread_work wk_msg_recvd;
+ struct kthread_work wk_timeout;
+ struct kthread_work wk_clean;
+ struct kthread_work wk_wait;
+ struct kthread_work wk_stream;
+
+ int (*hdcp_app_init)(struct hdcp_lib_handle *handle);
+ int (*hdcp_txmtr_init)(struct hdcp_lib_handle *handle);
+};
+
+struct hdcp_lib_message_map {
+ int msg_id;
+ const char *msg_name;
+};
+
+struct msm_hdcp_mgr {
+ struct platform_device *pdev;
+ dev_t dev_num;
+ struct cdev cdev;
+ struct class *class;
+ struct device *device;
+ struct HDCP_V2V1_MSG_TOPOLOGY cached_tp;
+ u32 tp_msgid;
+ void *client_ctx;
+ struct hdcp_lib_handle *handle;
+};
+
+static struct msm_hdcp_mgr *hdcp_drv_mgr;
+static struct hdcp_lib_handle *drv_client_handle;
+
+static void hdcp_lib_clean(struct hdcp_lib_handle *handle);
+static void hdcp_lib_init(struct hdcp_lib_handle *handle);
+static void hdcp_lib_msg_sent(struct hdcp_lib_handle *handle);
+static void hdcp_lib_msg_recvd(struct hdcp_lib_handle *handle);
+static void hdcp_lib_timeout(struct hdcp_lib_handle *handle);
+static void hdcp_lib_stream(struct hdcp_lib_handle *handle);
+static int hdcp_lib_txmtr_init(struct hdcp_lib_handle *handle);
+
+static struct qseecom_handle *hdcp1_handle;
+static bool hdcp1_supported = true;
+static bool hdcp1_enc_enabled;
+static struct mutex hdcp1_ta_cmd_lock;
+
+static const char *hdcp_lib_message_name(int msg_id)
+{
+ /*
+ * Message ID map. The first number indicates the message number
+ * assigned to the message by the HDCP 2.2 spec. This is also the first
+ * byte of every HDCP 2.2 authentication protocol message.
+ */
+ static struct hdcp_lib_message_map hdcp_lib_msg_map[] = {
+ {2, "AKE_INIT"},
+ {3, "AKE_SEND_CERT"},
+ {4, "AKE_NO_STORED_KM"},
+ {5, "AKE_STORED_KM"},
+ {7, "AKE_SEND_H_PRIME"},
+ {8, "AKE_SEND_PAIRING_INFO"},
+ {9, "LC_INIT"},
+ {10, "LC_SEND_L_PRIME"},
+ {11, "SKE_SEND_EKS"},
+ {12, "REPEATER_AUTH_SEND_RECEIVERID_LIST"},
+ {15, "REPEATER_AUTH_SEND_ACK"},
+ {16, "REPEATER_AUTH_STREAM_MANAGE"},
+ {17, "REPEATER_AUTH_STREAM_READY"},
+ {18, "SKE_SEND_TYPE_ID"},
+ };
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(hdcp_lib_msg_map); i++) {
+ if (msg_id == hdcp_lib_msg_map[i].msg_id)
+ return hdcp_lib_msg_map[i].msg_name;
+ }
+ return "UNKNOWN";
+}
+
+static int hdcp_lib_get_next_message(struct hdcp_lib_handle *handle,
+ struct hdcp_wakeup_data *data)
+{
+ switch (handle->last_msg) {
+ case INVALID_MESSAGE_ID:
+ return AKE_INIT_MESSAGE_ID;
+ case AKE_INIT_MESSAGE_ID:
+ return AKE_SEND_CERT_MESSAGE_ID;
+ case AKE_SEND_CERT_MESSAGE_ID:
+ if (handle->no_stored_km_flag)
+ return AKE_NO_STORED_KM_MESSAGE_ID;
+ else
+ return AKE_STORED_KM_MESSAGE_ID;
+ case AKE_STORED_KM_MESSAGE_ID:
+ case AKE_NO_STORED_KM_MESSAGE_ID:
+ return AKE_SEND_H_PRIME_MESSAGE_ID;
+ case AKE_SEND_H_PRIME_MESSAGE_ID:
+ if (handle->no_stored_km_flag)
+ return AKE_SEND_PAIRING_INFO_MESSAGE_ID;
+ else
+ return LC_INIT_MESSAGE_ID;
+ case AKE_SEND_PAIRING_INFO_MESSAGE_ID:
+ return LC_INIT_MESSAGE_ID;
+ case LC_INIT_MESSAGE_ID:
+ return LC_SEND_L_PRIME_MESSAGE_ID;
+ case LC_SEND_L_PRIME_MESSAGE_ID:
+ return SKE_SEND_EKS_MESSAGE_ID;
+ case SKE_SEND_EKS_MESSAGE_ID:
+ if (!handle->repeater_flag)
+ return SKE_SEND_TYPE_ID;
+ case SKE_SEND_TYPE_ID:
+ case REPEATER_AUTH_STREAM_READY_MESSAGE_ID:
+ case REPEATER_AUTH_SEND_ACK_MESSAGE_ID:
+ if (!handle->repeater_flag)
+ return INVALID_MESSAGE_ID;
+
+ if (data->cmd == HDCP_WKUP_CMD_SEND_MESSAGE)
+ return REPEATER_AUTH_STREAM_MANAGE_MESSAGE_ID;
+ else
+ return REPEATER_AUTH_SEND_RECEIVERID_LIST_MESSAGE_ID;
+ case REPEATER_AUTH_SEND_RECEIVERID_LIST_MESSAGE_ID:
+ return REPEATER_AUTH_SEND_ACK_MESSAGE_ID;
+ case REPEATER_AUTH_STREAM_MANAGE_MESSAGE_ID:
+ return REPEATER_AUTH_STREAM_READY_MESSAGE_ID;
+ default:
+ pr_err("Uknown message ID (%d)", handle->last_msg);
+ return -EINVAL;
+ }
+}
+
+static void hdcp_lib_wait_for_response(struct hdcp_lib_handle *handle,
+ struct hdcp_wakeup_data *data)
+{
+ switch (handle->last_msg) {
+ case AKE_SEND_H_PRIME_MESSAGE_ID:
+ if (handle->no_stored_km_flag)
+ handle->wait_timeout = HZ;
+ else
+ handle->wait_timeout = HZ / 4;
+ break;
+ case AKE_SEND_PAIRING_INFO_MESSAGE_ID:
+ handle->wait_timeout = HZ / 4;
+ break;
+ case REPEATER_AUTH_SEND_RECEIVERID_LIST_MESSAGE_ID:
+ if (!handle->authenticated)
+ handle->wait_timeout = HZ * 3;
+ else
+ handle->wait_timeout = 0;
+ break;
+ default:
+ handle->wait_timeout = 0;
+ }
+
+ if (handle->wait_timeout)
+ kthread_queue_work(&handle->worker, &handle->wk_wait);
+}
+
+static void hdcp_lib_wakeup_client(struct hdcp_lib_handle *handle,
+ struct hdcp_wakeup_data *data)
+{
+ int rc = 0, i;
+
+ if (!handle || !handle->client_ops || !handle->client_ops->wakeup ||
+ !data || (data->cmd == HDCP_WKUP_CMD_INVALID))
+ return;
+
+ data->abort_mask = REAUTH_REQ | LINK_INTEGRITY_FAILURE;
+
+ if (data->cmd == HDCP_WKUP_CMD_RECV_MESSAGE ||
+ data->cmd == HDCP_WKUP_CMD_LINK_POLL)
+ handle->last_msg = hdcp_lib_get_next_message(handle, data);
+
+ if (handle->last_msg != INVALID_MESSAGE_ID &&
+ data->cmd != HDCP_WKUP_CMD_STATUS_SUCCESS &&
+ data->cmd != HDCP_WKUP_CMD_STATUS_FAILED) {
+ u32 msg_num, rx_status;
+ const struct hdcp_msg_part *msg;
+
+ pr_debug("lib->client: %s (%s)\n",
+ hdcp_cmd_to_str(data->cmd),
+ hdcp_lib_message_name(handle->last_msg));
+
+ data->message_data = &hdcp_msg_lookup[handle->last_msg];
+
+ msg_num = data->message_data->num_messages;
+ msg = data->message_data->messages;
+ rx_status = data->message_data->rx_status;
+
+ pr_debug("%10s | %6s | %4s\n", "name", "offset", "len");
+
+ for (i = 0; i < msg_num; i++)
+ pr_debug("%10s | %6x | %4d\n",
+ msg[i].name, msg[i].offset,
+ msg[i].length);
+ } else {
+ pr_debug("lib->client: %s\n", hdcp_cmd_to_str(data->cmd));
+ }
+
+ rc = handle->client_ops->wakeup(data);
+ if (rc)
+ pr_err("error sending %s to client\n",
+ hdcp_cmd_to_str(data->cmd));
+
+ hdcp_lib_wait_for_response(handle, data);
+}
+
+static inline void hdcp_lib_send_message(struct hdcp_lib_handle *handle)
+{
+ char msg_name[50];
+ struct hdcp_wakeup_data cdata = {
+ HDCP_WKUP_CMD_SEND_MESSAGE
+ };
+
+ cdata.context = handle->client_ctx;
+ cdata.send_msg_buf = handle->listener_buf;
+ cdata.send_msg_len = handle->msglen;
+ cdata.timeout = handle->hdcp_timeout;
+
+ snprintf(msg_name, sizeof(msg_name), "%s: ",
+ hdcp_lib_message_name((int)cdata.send_msg_buf[0]));
+
+ print_hex_dump(KERN_DEBUG, msg_name,
+ DUMP_PREFIX_NONE, 16, 1, cdata.send_msg_buf,
+ cdata.send_msg_len, false);
+
+ hdcp_lib_wakeup_client(handle, &cdata);
+}
+
+static int hdcp_lib_enable_encryption(struct hdcp_lib_handle *handle)
+{
+ int rc = 0;
+ struct hdcp_set_hw_key_req *req_buf;
+ struct hdcp_set_hw_key_rsp *rsp_buf;
+
+ if (!handle || !handle->qseecom_handle ||
+ !handle->qseecom_handle->sbuf) {
+ pr_err("invalid handle\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ /*
+ * wait at least 200ms before enabling encryption
+ * as per hdcp2p2 sepcifications.
+ */
+ msleep(SLEEP_SET_HW_KEY_MS);
+
+ req_buf = (struct hdcp_set_hw_key_req *)(handle->qseecom_handle->sbuf);
+ req_buf->commandid = HDCP_TXMTR_SET_HW_KEY;
+ req_buf->ctxhandle = handle->tz_ctxhandle;
+
+ rsp_buf = (struct hdcp_set_hw_key_rsp *)
+ (handle->qseecom_handle->sbuf +
+ QSEECOM_ALIGN(sizeof(struct hdcp_set_hw_key_req)));
+
+ rc = qseecom_send_command(handle->qseecom_handle, req_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp_set_hw_key_req)),
+ rsp_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp_set_hw_key_rsp)));
+
+ if ((rc < 0) || (rsp_buf->status < 0)) {
+ pr_err("qseecom cmd failed with err = %d status = %d\n",
+ rc, rsp_buf->status);
+ rc = -EINVAL;
+ goto error;
+ }
+
+ /* reached an authenticated state */
+ handle->hdcp_state |= HDCP_STATE_AUTHENTICATED;
+
+ pr_debug("success\n");
+ return 0;
+error:
+ if (handle && !atomic_read(&handle->hdcp_off))
+ HDCP_LIB_EXECUTE(clean);
+
+ return rc;
+}
+
+static int hdcp_lib_get_version(struct hdcp_lib_handle *handle)
+{
+ int rc = 0;
+ struct hdcp_version_req *req_buf;
+ struct hdcp_version_rsp *rsp_buf;
+ uint32_t app_major_version = 0;
+
+ if (!handle) {
+ pr_err("invalid input\n");
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
+ pr_err("library not loaded\n");
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ /* get the TZ hdcp2p2 app version */
+ req_buf = (struct hdcp_version_req *)handle->qseecom_handle->sbuf;
+ req_buf->commandid = HDCP_TXMTR_GET_VERSION;
+
+ rsp_buf = (struct hdcp_version_rsp *)
+ (handle->qseecom_handle->sbuf +
+ QSEECOM_ALIGN(sizeof(struct hdcp_version_req)));
+
+ rc = qseecom_send_command(handle->qseecom_handle,
+ req_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp_lib_init_req)),
+ rsp_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp_lib_init_rsp)));
+
+ if (rc < 0) {
+ pr_err("qseecom cmd failed err = %d\n", rc);
+ goto exit;
+ }
+
+ app_major_version = HCDP_TXMTR_GET_MAJOR_VERSION(rsp_buf->appversion);
+
+ pr_debug("hdcp2p2 app major version %d, app version %d\n",
+ app_major_version, rsp_buf->appversion);
+
+exit:
+ return rc;
+}
+
+static int hdcp_lib_verify_keys(struct hdcp_lib_handle *handle)
+{
+ int rc = -EINVAL;
+ struct hdcp_verify_key_req *req_buf;
+ struct hdcp_verify_key_rsp *rsp_buf;
+
+ if (!handle) {
+ pr_err("invalid input\n");
+ goto exit;
+ }
+
+ if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
+ pr_err("app not loaded\n");
+ goto exit;
+ }
+
+ req_buf = (struct hdcp_verify_key_req *)handle->qseecom_handle->sbuf;
+ req_buf->commandid = HDCP_TXMTR_VERIFY_KEY;
+
+ rsp_buf = (struct hdcp_verify_key_rsp *)
+ (handle->qseecom_handle->sbuf +
+ QSEECOM_ALIGN(sizeof(struct hdcp_verify_key_req)));
+
+ rc = qseecom_send_command(handle->qseecom_handle,
+ req_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp_verify_key_req)),
+ rsp_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp_verify_key_rsp)));
+
+ if (rc < 0) {
+ pr_err("qseecom cmd failed err = %d\n", rc);
+ goto exit;
+ }
+
+ return rsp_buf->status;
+exit:
+ return rc;
+}
+
+static int hdcp_app_init(struct hdcp_lib_handle *handle)
+{
+ int rc = 0;
+ struct hdcp_lib_init_req *req_buf;
+ struct hdcp_lib_init_rsp *rsp_buf;
+ uint32_t app_minor_version = 0;
+
+ if (!handle) {
+ pr_err("invalid input\n");
+ goto exit;
+ }
+
+ if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
+ pr_err("library not loaded\n");
+ goto exit;
+ }
+
+ /* now load the app by sending hdcp_lib_init */
+ req_buf = (struct hdcp_lib_init_req *)handle->qseecom_handle->sbuf;
+ req_buf->commandid = HDCP_LIB_INIT;
+ req_buf->clientversion =
+ HDCP_CLIENT_MAKE_VERSION(HDCP_CLIENT_MAJOR_VERSION,
+ HDCP_CLIENT_MINOR_VERSION,
+ HDCP_CLIENT_PATCH_VERSION);
+ rsp_buf = (struct hdcp_lib_init_rsp *)
+ (handle->qseecom_handle->sbuf +
+ QSEECOM_ALIGN(sizeof(struct hdcp_lib_init_req)));
+
+ rc = qseecom_send_command(handle->qseecom_handle,
+ req_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp_lib_init_req)),
+ rsp_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp_lib_init_rsp)));
+
+ if (rc < 0) {
+ pr_err("qseecom cmd failed err = %d\n", rc);
+ goto exit;
+ }
+
+ app_minor_version = HCDP_TXMTR_GET_MINOR_VERSION(rsp_buf->appversion);
+ if (app_minor_version != HDCP_CLIENT_MINOR_VERSION) {
+ pr_err
+ ("client-app minor version mismatch app(%d), client(%d)\n",
+ app_minor_version, HDCP_CLIENT_MINOR_VERSION);
+ rc = -1;
+ goto exit;
+ }
+ pr_debug("success\n");
+ pr_debug("client version major(%d), minor(%d), patch(%d)\n",
+ HDCP_CLIENT_MAJOR_VERSION, HDCP_CLIENT_MINOR_VERSION,
+ HDCP_CLIENT_PATCH_VERSION);
+ pr_debug("app version major(%d), minor(%d), patch(%d)\n",
+ HCDP_TXMTR_GET_MAJOR_VERSION(rsp_buf->appversion),
+ HCDP_TXMTR_GET_MINOR_VERSION(rsp_buf->appversion),
+ HCDP_TXMTR_GET_PATCH_VERSION(rsp_buf->appversion));
+
+exit:
+ return rc;
+}
+
+static int hdcp_lib_library_load(struct hdcp_lib_handle *handle)
+{
+ int rc = 0;
+
+ if (!handle) {
+ pr_err("invalid input\n");
+ goto exit;
+ }
+
+ if (handle->hdcp_state & HDCP_STATE_APP_LOADED) {
+ pr_err("library already loaded\n");
+ goto exit;
+ }
+
+ /*
+ * allocating resource for qseecom handle
+ * the app is not loaded here
+ */
+ rc = qseecom_start_app(&(handle->qseecom_handle),
+ TZAPP_NAME, QSEECOM_SBUFF_SIZE);
+ if (rc) {
+ pr_err("qseecom_start_app failed %d\n", rc);
+ goto exit;
+ }
+
+ handle->hdcp_state |= HDCP_STATE_APP_LOADED;
+ pr_debug("qseecom_start_app success\n");
+
+ rc = hdcp_lib_get_version(handle);
+ if (rc) {
+ pr_err("library get version failed\n");
+ goto exit;
+ }
+
+ handle->hdcp_app_init = hdcp_app_init;
+ handle->hdcp_txmtr_init = hdcp_lib_txmtr_init;
+
+ if (handle->hdcp_app_init == NULL) {
+ pr_err("invalid app init function pointer\n");
+ goto exit;
+ }
+
+ rc = handle->hdcp_app_init(handle);
+ if (rc) {
+ pr_err("app init failed\n");
+ goto exit;
+ }
+exit:
+ return rc;
+}
+
+static int hdcp_lib_library_unload(struct hdcp_lib_handle *handle)
+{
+ int rc = 0;
+ struct hdcp_lib_deinit_req *req_buf;
+ struct hdcp_lib_deinit_rsp *rsp_buf;
+
+ if (!handle || !handle->qseecom_handle ||
+ !handle->qseecom_handle->sbuf) {
+ pr_err("invalid handle\n");
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
+ pr_err("library not loaded\n");
+ return rc;
+ }
+
+ /* unloading app by sending hdcp_lib_deinit cmd */
+ req_buf = (struct hdcp_lib_deinit_req *)handle->qseecom_handle->sbuf;
+ req_buf->commandid = HDCP_LIB_DEINIT;
+ rsp_buf = (struct hdcp_lib_deinit_rsp *)
+ (handle->qseecom_handle->sbuf +
+ QSEECOM_ALIGN(sizeof(struct hdcp_lib_deinit_req)));
+
+ rc = qseecom_send_command(handle->qseecom_handle,
+ req_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp_lib_deinit_req)),
+ rsp_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp_lib_deinit_rsp)));
+
+ if (rc < 0) {
+ pr_err("qseecom cmd failed err = %d\n", rc);
+ goto exit;
+ }
+
+ /* deallocate the resources for qseecom handle */
+ rc = qseecom_shutdown_app(&handle->qseecom_handle);
+ if (rc) {
+ pr_err("qseecom_shutdown_app failed err: %d\n", rc);
+ goto exit;
+ }
+
+ handle->hdcp_state &= ~HDCP_STATE_APP_LOADED;
+ pr_debug("success\n");
+exit:
+ return rc;
+}
+
+static int hdcp_lib_session_init(struct hdcp_lib_handle *handle)
+{
+ int rc = 0;
+ struct hdcp_lib_session_init_req *req_buf;
+ struct hdcp_lib_session_init_rsp *rsp_buf;
+
+ if (!handle || !handle->qseecom_handle ||
+ !handle->qseecom_handle->sbuf) {
+ pr_err("invalid handle\n");
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
+ pr_err("app not loaded\n");
+ goto exit;
+ }
+
+ if (handle->hdcp_state & HDCP_STATE_SESSION_INIT) {
+ pr_err("session already initialized\n");
+ goto exit;
+ }
+
+ /* send HDCP_Session_Init command to TZ */
+ req_buf =
+ (struct hdcp_lib_session_init_req *)handle->qseecom_handle->sbuf;
+ req_buf->commandid = HDCP_SESSION_INIT;
+ req_buf->deviceid = handle->device_type;
+ rsp_buf = (struct hdcp_lib_session_init_rsp *)
+ (handle->qseecom_handle->sbuf +
+ QSEECOM_ALIGN(sizeof(struct hdcp_lib_session_init_req)));
+
+ rc = qseecom_send_command(handle->qseecom_handle, req_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct
+ hdcp_lib_session_init_req)),
+ rsp_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct
+ hdcp_lib_session_init_rsp)));
+
+ if ((rc < 0) || (rsp_buf->status != HDCP_SUCCESS) ||
+ (rsp_buf->commandid != HDCP_SESSION_INIT)) {
+ pr_err("qseecom cmd failed with err = %d, status = %d\n",
+ rc, rsp_buf->status);
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ pr_debug("session id %d\n", rsp_buf->sessionid);
+
+ handle->session_id = rsp_buf->sessionid;
+ handle->hdcp_state |= HDCP_STATE_SESSION_INIT;
+
+ pr_debug("success\n");
+exit:
+ return rc;
+}
+
+static int hdcp_lib_session_deinit(struct hdcp_lib_handle *handle)
+{
+ int rc = 0;
+ struct hdcp_lib_session_deinit_req *req_buf;
+ struct hdcp_lib_session_deinit_rsp *rsp_buf;
+
+ if (!handle || !handle->qseecom_handle ||
+ !handle->qseecom_handle->sbuf) {
+ pr_err("invalid handle\n");
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
+ pr_err("app not loaded\n");
+ goto exit;
+ }
+
+ if (!(handle->hdcp_state & HDCP_STATE_SESSION_INIT)) {
+ /* unload library here */
+ pr_err("session not initialized\n");
+ goto exit;
+ }
+
+ /* send command to TZ */
+ req_buf =
+ (struct hdcp_lib_session_deinit_req *)handle->qseecom_handle->sbuf;
+ req_buf->commandid = HDCP_SESSION_DEINIT;
+ req_buf->sessionid = handle->session_id;
+ rsp_buf = (struct hdcp_lib_session_deinit_rsp *)
+ (handle->qseecom_handle->sbuf +
+ QSEECOM_ALIGN(sizeof(struct hdcp_lib_session_deinit_req)));
+
+ rc = qseecom_send_command(handle->qseecom_handle, req_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct
+ hdcp_lib_session_deinit_req)),
+ rsp_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct
+ hdcp_lib_session_deinit_rsp)));
+
+ if ((rc < 0) || (rsp_buf->status < 0) ||
+ (rsp_buf->commandid != HDCP_SESSION_DEINIT)) {
+ pr_err("qseecom cmd failed with err = %d status = %d\n",
+ rc, rsp_buf->status);
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ handle->hdcp_state &= ~HDCP_STATE_SESSION_INIT;
+ pr_debug("success\n");
+exit:
+ return rc;
+}
+
+static int hdcp_lib_txmtr_init(struct hdcp_lib_handle *handle)
+{
+ int rc = 0;
+ struct hdcp_tx_init_req *req_buf;
+ struct hdcp_tx_init_rsp *rsp_buf;
+
+ if (!handle || !handle->qseecom_handle ||
+ !handle->qseecom_handle->sbuf) {
+ pr_err("invalid handle\n");
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ if (!(handle->hdcp_state & HDCP_STATE_SESSION_INIT)) {
+ pr_err("session not initialized\n");
+ goto exit;
+ }
+
+ if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
+ pr_err("library not loaded\n");
+ goto exit;
+ }
+
+ /* send HDCP_Txmtr_Init command to TZ */
+ req_buf = (struct hdcp_tx_init_req *)handle->qseecom_handle->sbuf;
+ req_buf->commandid = HDCP_TXMTR_INIT;
+ req_buf->sessionid = handle->session_id;
+ rsp_buf = (struct hdcp_tx_init_rsp *)
+ (handle->qseecom_handle->sbuf +
+ QSEECOM_ALIGN(sizeof(struct hdcp_tx_init_req)));
+
+ rc = qseecom_send_command(handle->qseecom_handle, req_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp_tx_init_req)),
+ rsp_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp_tx_init_rsp)));
+
+ if ((rc < 0) || (rsp_buf->status != HDCP_SUCCESS) ||
+ (rsp_buf->commandid != HDCP_TXMTR_INIT)) {
+ pr_err("qseecom cmd failed with err = %d, status = %d\n",
+ rc, rsp_buf->status);
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ handle->tz_ctxhandle = rsp_buf->ctxhandle;
+ handle->hdcp_state |= HDCP_STATE_TXMTR_INIT;
+
+ pr_debug("success\n");
+exit:
+ return rc;
+}
+
+static int hdcp_lib_txmtr_deinit(struct hdcp_lib_handle *handle)
+{
+ int rc = 0;
+ struct hdcp_deinit_req *req_buf;
+ struct hdcp_deinit_rsp *rsp_buf;
+
+ if (!handle || !handle->qseecom_handle ||
+ !handle->qseecom_handle->sbuf) {
+ pr_err("invalid handle\n");
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
+ pr_err("app not loaded\n");
+ goto exit;
+ }
+
+ if (!(handle->hdcp_state & HDCP_STATE_TXMTR_INIT)) {
+ /* unload library here */
+ pr_err("txmtr not initialized\n");
+ goto exit;
+ }
+
+ /* send command to TZ */
+ req_buf = (struct hdcp_deinit_req *)handle->qseecom_handle->sbuf;
+ req_buf->commandid = HDCP_TXMTR_DEINIT;
+ req_buf->ctxhandle = handle->tz_ctxhandle;
+ rsp_buf = (struct hdcp_deinit_rsp *)
+ (handle->qseecom_handle->sbuf +
+ QSEECOM_ALIGN(sizeof(struct hdcp_deinit_req)));
+
+ rc = qseecom_send_command(handle->qseecom_handle, req_buf,
+ QSEECOM_ALIGN(sizeof(struct hdcp_deinit_req)),
+ rsp_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp_deinit_rsp)));
+
+ if ((rc < 0) || (rsp_buf->status < 0) ||
+ (rsp_buf->commandid != HDCP_TXMTR_DEINIT)) {
+ pr_err("qseecom cmd failed with err = %d status = %d\n",
+ rc, rsp_buf->status);
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ handle->hdcp_state &= ~HDCP_STATE_TXMTR_INIT;
+ pr_debug("success\n");
+exit:
+ return rc;
+}
+
+static int hdcp_lib_start_auth(struct hdcp_lib_handle *handle)
+{
+ int rc = 0;
+ struct hdcp_start_auth_req *req_buf;
+ struct hdcp_start_auth_rsp *rsp_buf;
+
+ if (!handle || !handle->qseecom_handle ||
+ !handle->qseecom_handle->sbuf) {
+ pr_err("invalid handle\n");
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ if (!(handle->hdcp_state & HDCP_STATE_SESSION_INIT)) {
+ pr_err("session not initialized\n");
+ goto exit;
+ }
+
+ if (!(handle->hdcp_state & HDCP_STATE_TXMTR_INIT)) {
+ pr_err("txmtr not initialized\n");
+ goto exit;
+ }
+
+ /* send HDCP_Txmtr_Start_Auth command to TZ */
+ req_buf = (struct hdcp_start_auth_req *)handle->qseecom_handle->sbuf;
+ req_buf->commandid = HDCP_TXMTR_START_AUTHENTICATE;
+ req_buf->ctxHandle = handle->tz_ctxhandle;
+ rsp_buf = (struct hdcp_start_auth_rsp *)
+ (handle->qseecom_handle->sbuf +
+ QSEECOM_ALIGN(sizeof(struct hdcp_start_auth_req)));
+
+ rc = qseecom_send_command(handle->qseecom_handle, req_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp_start_auth_req)),
+ rsp_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp_start_auth_rsp)));
+
+ if ((rc < 0) || (rsp_buf->status != HDCP_SUCCESS) ||
+ (rsp_buf->commandid != HDCP_TXMTR_START_AUTHENTICATE) ||
+ (rsp_buf->msglen <= 0) || (rsp_buf->message == NULL)) {
+ pr_err("qseecom cmd failed with err = %d, status = %d\n",
+ rc, rsp_buf->status);
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ pr_debug("recvd %s from TZ at %dms\n",
+ hdcp_lib_message_name((int)rsp_buf->message[0]),
+ jiffies_to_msecs(jiffies));
+
+ handle->last_msg = (int)rsp_buf->message[0];
+
+ /* send the response to HDMI driver */
+ memset(handle->listener_buf, 0, MAX_TX_MESSAGE_SIZE);
+ memcpy(handle->listener_buf, (unsigned char *)rsp_buf->message,
+ rsp_buf->msglen);
+ handle->msglen = rsp_buf->msglen;
+ handle->hdcp_timeout = rsp_buf->timeout;
+
+ handle->tz_ctxhandle = rsp_buf->ctxhandle;
+
+ pr_debug("success\n");
+exit:
+ return rc;
+}
+
+static void hdcp_lib_stream(struct hdcp_lib_handle *handle)
+{
+ int rc = 0;
+ struct hdcp_query_stream_type_req *req_buf;
+ struct hdcp_query_stream_type_rsp *rsp_buf;
+
+ if (!handle || !handle->qseecom_handle ||
+ !handle->qseecom_handle->sbuf) {
+ pr_err("invalid handle\n");
+ return;
+ }
+
+ if (atomic_read(&handle->hdcp_off)) {
+ pr_debug("invalid state, hdcp off\n");
+ return;
+ }
+
+ if (!handle->repeater_flag) {
+ pr_debug("invalid state, not a repeater\n");
+ return;
+ }
+
+ /* send command to TZ */
+ req_buf =
+ (struct hdcp_query_stream_type_req *)handle->qseecom_handle->sbuf;
+ req_buf->commandid = HDCP_TXMTR_QUERY_STREAM_TYPE;
+ req_buf->ctxhandle = handle->tz_ctxhandle;
+ rsp_buf = (struct hdcp_query_stream_type_rsp *)
+ (handle->qseecom_handle->sbuf +
+ QSEECOM_ALIGN(sizeof(struct hdcp_query_stream_type_req)));
+
+ rc = qseecom_send_command(handle->qseecom_handle, req_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct
+ hdcp_query_stream_type_req)),
+ rsp_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct
+ hdcp_query_stream_type_rsp)));
+
+ if ((rc < 0) || (rsp_buf->status < 0) || (rsp_buf->msglen <= 0) ||
+ (rsp_buf->commandid != HDCP_TXMTR_QUERY_STREAM_TYPE) ||
+ (rsp_buf->msg == NULL)) {
+ pr_err("qseecom cmd failed with err=%d status=%d\n",
+ rc, rsp_buf->status);
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ pr_debug("message received from TZ: %s\n",
+ hdcp_lib_message_name((int)rsp_buf->msg[0]));
+
+ handle->last_msg = (int)rsp_buf->msg[0];
+
+ memset(handle->listener_buf, 0, MAX_TX_MESSAGE_SIZE);
+ memcpy(handle->listener_buf, (unsigned char *)rsp_buf->msg,
+ rsp_buf->msglen);
+ handle->hdcp_timeout = rsp_buf->timeout;
+ handle->msglen = rsp_buf->msglen;
+exit:
+ if (!rc && !atomic_read(&handle->hdcp_off))
+ hdcp_lib_send_message(handle);
+}
+
+static void hdcp_lib_query_stream_work(struct kthread_work *work)
+{
+ struct hdcp_lib_handle *handle = container_of(work,
+ struct hdcp_lib_handle,
+ wk_stream);
+
+ hdcp_lib_stream(handle);
+}
+
+static bool hdcp_lib_client_feature_supported(void *phdcpcontext)
+{
+ int rc = 0;
+ bool supported = false;
+ struct hdcp_lib_handle *handle = phdcpcontext;
+
+ if (!handle) {
+ pr_err("invalid input\n");
+ goto exit;
+ }
+
+ if (handle->feature_supported) {
+ supported = true;
+ goto exit;
+ }
+
+ rc = hdcp_lib_library_load(handle);
+ if (!rc) {
+ if (!hdcp_lib_verify_keys(handle)) {
+ pr_debug("HDCP2p2 supported\n");
+ handle->feature_supported = true;
+ supported = true;
+ }
+ hdcp_lib_library_unload(handle);
+ }
+exit:
+ return supported;
+}
+
+static void hdcp_lib_check_worker_status(struct hdcp_lib_handle *handle)
+{
+ if (!list_empty(&handle->wk_init.node))
+ pr_debug("init work queued\n");
+
+ if (handle->worker.current_work == &handle->wk_init)
+ pr_debug("init work executing\n");
+
+ if (!list_empty(&handle->wk_msg_sent.node))
+ pr_debug("msg_sent work queued\n");
+
+ if (handle->worker.current_work == &handle->wk_msg_sent)
+ pr_debug("msg_sent work executing\n");
+
+ if (!list_empty(&handle->wk_msg_recvd.node))
+ pr_debug("msg_recvd work queued\n");
+
+ if (handle->worker.current_work == &handle->wk_msg_recvd)
+ pr_debug("msg_recvd work executing\n");
+
+ if (!list_empty(&handle->wk_timeout.node))
+ pr_debug("timeout work queued\n");
+
+ if (handle->worker.current_work == &handle->wk_timeout)
+ pr_debug("timeout work executing\n");
+
+ if (!list_empty(&handle->wk_clean.node))
+ pr_debug("clean work queued\n");
+
+ if (handle->worker.current_work == &handle->wk_clean)
+ pr_debug("clean work executing\n");
+
+ if (!list_empty(&handle->wk_wait.node))
+ pr_debug("wait work queued\n");
+
+ if (handle->worker.current_work == &handle->wk_wait)
+ pr_debug("wait work executing\n");
+
+ if (!list_empty(&handle->wk_stream.node))
+ pr_debug("stream work queued\n");
+
+ if (handle->worker.current_work == &handle->wk_stream)
+ pr_debug("stream work executing\n");
+}
+
+static int hdcp_lib_check_valid_state(struct hdcp_lib_handle *handle)
+{
+ int rc = 0;
+
+ if (!list_empty(&handle->worker.work_list))
+ hdcp_lib_check_worker_status(handle);
+
+ if (handle->wakeup_cmd == HDCP_LIB_WKUP_CMD_START) {
+ if (!list_empty(&handle->worker.work_list)) {
+ pr_debug("error: queue not empty\n");
+ rc = -EBUSY;
+ goto exit;
+ }
+
+ if (handle->hdcp_state & HDCP_STATE_APP_LOADED) {
+ pr_debug("library already loaded\n");
+ rc = -EBUSY;
+ goto exit;
+ }
+ } else {
+ if (atomic_read(&handle->hdcp_off)) {
+ pr_debug("hdcp2.2 session tearing down\n");
+ goto exit;
+ }
+
+ if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
+ pr_debug("hdcp 2.2 app not loaded\n");
+ goto exit;
+ }
+ }
+exit:
+ return rc;
+}
+
+static int hdcp_lib_wakeup_thread(struct hdcp_lib_wakeup_data *data)
+{
+ struct hdcp_lib_handle *handle;
+ int rc = 0;
+
+ if (!data)
+ return -EINVAL;
+
+ handle = data->context;
+ if (!handle)
+ return -EINVAL;
+
+ mutex_lock(&handle->wakeup_mutex);
+
+ handle->wakeup_cmd = data->cmd;
+ handle->timeout_left = data->timeout;
+
+ pr_debug("client->lib: %s (%s)\n",
+ hdcp_lib_cmd_to_str(data->cmd),
+ hdcp_lib_message_name(handle->last_msg));
+
+ rc = hdcp_lib_check_valid_state(handle);
+ if (rc)
+ goto exit;
+
+ mutex_lock(&handle->msg_lock);
+ if (data->recvd_msg_len) {
+ kzfree(handle->last_msg_recvd_buf);
+
+ handle->last_msg_recvd_len = data->recvd_msg_len;
+ handle->last_msg_recvd_buf = kzalloc(data->recvd_msg_len,
+ GFP_KERNEL);
+ if (!handle->last_msg_recvd_buf) {
+ rc = -ENOMEM;
+ mutex_unlock(&handle->msg_lock);
+ goto exit;
+ }
+
+ memcpy(handle->last_msg_recvd_buf, data->recvd_msg_buf,
+ data->recvd_msg_len);
+ }
+ mutex_unlock(&handle->msg_lock);
+
+ if (!completion_done(&handle->poll_wait))
+ complete_all(&handle->poll_wait);
+
+ switch (handle->wakeup_cmd) {
+ case HDCP_LIB_WKUP_CMD_START:
+ handle->no_stored_km_flag = 0;
+ handle->repeater_flag = false;
+ handle->update_stream = false;
+ handle->last_msg_sent = 0;
+ handle->last_msg = INVALID_MESSAGE_ID;
+ handle->hdcp_timeout = 0;
+ handle->timeout_left = 0;
+ atomic_set(&handle->hdcp_off, 0);
+ handle->hdcp_state = HDCP_STATE_INIT;
+
+ HDCP_LIB_EXECUTE(init);
+ break;
+ case HDCP_LIB_WKUP_CMD_STOP:
+ atomic_set(&handle->hdcp_off, 1);
+
+ HDCP_LIB_EXECUTE(clean);
+ break;
+ case HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS:
+ handle->last_msg_sent = handle->listener_buf[0];
+
+ HDCP_LIB_EXECUTE(msg_sent);
+ break;
+ case HDCP_LIB_WKUP_CMD_MSG_SEND_FAILED:
+ case HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED:
+ case HDCP_LIB_WKUP_CMD_LINK_FAILED:
+ handle->hdcp_state |= HDCP_STATE_ERROR;
+ HDCP_LIB_EXECUTE(clean);
+ break;
+ case HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS:
+ HDCP_LIB_EXECUTE(msg_recvd);
+ break;
+ case HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT:
+ HDCP_LIB_EXECUTE(timeout);
+ break;
+ case HDCP_LIB_WKUP_CMD_QUERY_STREAM_TYPE:
+ HDCP_LIB_EXECUTE(stream);
+ break;
+ default:
+ pr_err("invalid wakeup command %d\n", handle->wakeup_cmd);
+ }
+exit:
+ mutex_unlock(&handle->wakeup_mutex);
+
+ return rc;
+}
+
+static void hdcp_lib_msg_sent(struct hdcp_lib_handle *handle)
+{
+ struct hdcp_wakeup_data cdata = { HDCP_WKUP_CMD_INVALID };
+
+ if (!handle) {
+ pr_err("invalid handle\n");
+ return;
+ }
+
+ cdata.context = handle->client_ctx;
+
+ switch (handle->last_msg_sent) {
+ case SKE_SEND_TYPE_ID:
+ if (!hdcp_lib_enable_encryption(handle)) {
+ handle->authenticated = true;
+
+ cdata.cmd = HDCP_WKUP_CMD_STATUS_SUCCESS;
+ hdcp_lib_wakeup_client(handle, &cdata);
+ }
+
+ /* poll for link check */
+ cdata.cmd = HDCP_WKUP_CMD_LINK_POLL;
+ break;
+ case SKE_SEND_EKS_MESSAGE_ID:
+ if (handle->repeater_flag) {
+ /* poll for link check */
+ cdata.cmd = HDCP_WKUP_CMD_LINK_POLL;
+ } else {
+ memset(handle->listener_buf, 0, MAX_TX_MESSAGE_SIZE);
+ handle->listener_buf[0] = SKE_SEND_TYPE_ID;
+ handle->msglen = 2;
+ cdata.cmd = HDCP_WKUP_CMD_SEND_MESSAGE;
+ cdata.send_msg_buf = handle->listener_buf;
+ cdata.send_msg_len = handle->msglen;
+ handle->last_msg = hdcp_lib_get_next_message(handle,
+ &cdata);
+ }
+ break;
+ case REPEATER_AUTH_SEND_ACK_MESSAGE_ID:
+ pr_debug("Repeater authentication successful\n");
+
+ if (handle->update_stream) {
+ HDCP_LIB_EXECUTE(stream);
+ handle->update_stream = false;
+ } else {
+ cdata.cmd = HDCP_WKUP_CMD_LINK_POLL;
+ }
+ break;
+ default:
+ cdata.cmd = HDCP_WKUP_CMD_RECV_MESSAGE;
+ cdata.timeout = handle->timeout_left;
+ }
+
+ hdcp_lib_wakeup_client(handle, &cdata);
+}
+
+static void hdcp_lib_msg_sent_work(struct kthread_work *work)
+{
+ struct hdcp_lib_handle *handle = container_of(work,
+ struct hdcp_lib_handle,
+ wk_msg_sent);
+
+ if (handle->wakeup_cmd != HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS) {
+ pr_err("invalid wakeup command %d\n", handle->wakeup_cmd);
+ return;
+ }
+
+ hdcp_lib_msg_sent(handle);
+}
+
+static void hdcp_lib_init(struct hdcp_lib_handle *handle)
+{
+ int rc = 0;
+
+ if (!handle) {
+ pr_err("invalid handle\n");
+ return;
+ }
+
+ if (handle->wakeup_cmd != HDCP_LIB_WKUP_CMD_START) {
+ pr_err("invalid wakeup command %d\n", handle->wakeup_cmd);
+ return;
+ }
+
+ rc = hdcp_lib_library_load(handle);
+ if (rc)
+ goto exit;
+
+ rc = hdcp_lib_session_init(handle);
+ if (rc)
+ goto exit;
+
+ if (handle->hdcp_txmtr_init == NULL) {
+ pr_err("invalid txmtr init function pointer\n");
+ return;
+ }
+
+ rc = handle->hdcp_txmtr_init(handle);
+ if (rc)
+ goto exit;
+
+ rc = hdcp_lib_start_auth(handle);
+ if (rc)
+ goto exit;
+
+ hdcp_lib_send_message(handle);
+
+ return;
+exit:
+ HDCP_LIB_EXECUTE(clean);
+}
+
+static void hdcp_lib_init_work(struct kthread_work *work)
+{
+ struct hdcp_lib_handle *handle = container_of(work,
+ struct hdcp_lib_handle,
+ wk_init);
+
+ hdcp_lib_init(handle);
+}
+
+static void hdcp_lib_timeout(struct hdcp_lib_handle *handle)
+{
+ int rc = 0;
+ struct hdcp_send_timeout_req *req_buf;
+ struct hdcp_send_timeout_rsp *rsp_buf;
+
+ if (!handle || !handle->qseecom_handle ||
+ !handle->qseecom_handle->sbuf) {
+ pr_debug("invalid handle\n");
+ return;
+ }
+
+ if (atomic_read(&handle->hdcp_off)) {
+ pr_debug("invalid state, hdcp off\n");
+ return;
+ }
+
+ req_buf = (struct hdcp_send_timeout_req *)
+ (handle->qseecom_handle->sbuf);
+ req_buf->commandid = HDCP_TXMTR_SEND_MESSAGE_TIMEOUT;
+ req_buf->ctxhandle = handle->tz_ctxhandle;
+
+ rsp_buf = (struct hdcp_send_timeout_rsp *)
+ (handle->qseecom_handle->sbuf +
+ QSEECOM_ALIGN(sizeof(struct hdcp_send_timeout_req)));
+
+ rc = qseecom_send_command(handle->qseecom_handle, req_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp_send_timeout_req)),
+ rsp_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct
+ hdcp_send_timeout_rsp)));
+
+ if ((rc < 0) || (rsp_buf->status != HDCP_SUCCESS)) {
+ pr_err("qseecom cmd failed for with err = %d status = %d\n",
+ rc, rsp_buf->status);
+ rc = -EINVAL;
+ goto error;
+ }
+
+ if (rsp_buf->commandid == HDCP_TXMTR_SEND_MESSAGE_TIMEOUT) {
+ pr_err("HDCP_TXMTR_SEND_MESSAGE_TIMEOUT\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ /*
+ * if the response contains LC_Init message
+ * send the message again to TZ
+ */
+ if ((rsp_buf->commandid == HDCP_TXMTR_PROCESS_RECEIVED_MESSAGE) &&
+ ((int)rsp_buf->message[0] == LC_INIT_MESSAGE_ID) &&
+ (rsp_buf->msglen == LC_INIT_MESSAGE_SIZE)) {
+ if (!atomic_read(&handle->hdcp_off)) {
+ /* keep local copy of TZ response */
+ memset(handle->listener_buf, 0, MAX_TX_MESSAGE_SIZE);
+ memcpy(handle->listener_buf,
+ (unsigned char *)rsp_buf->message,
+ rsp_buf->msglen);
+ handle->hdcp_timeout = rsp_buf->timeout;
+ handle->msglen = rsp_buf->msglen;
+
+ hdcp_lib_send_message(handle);
+ }
+ }
+
+ return;
+error:
+ if (!atomic_read(&handle->hdcp_off))
+ HDCP_LIB_EXECUTE(clean);
+}
+
+static void hdcp_lib_manage_timeout_work(struct kthread_work *work)
+{
+ struct hdcp_lib_handle *handle = container_of(work,
+ struct hdcp_lib_handle,
+ wk_timeout);
+
+ hdcp_lib_timeout(handle);
+}
+
+static void hdcp_lib_clean(struct hdcp_lib_handle *handle)
+{
+ struct hdcp_wakeup_data cdata = { HDCP_WKUP_CMD_INVALID };
+
+ if (!handle) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ handle->authenticated = false;
+
+ hdcp_lib_txmtr_deinit(handle);
+ hdcp_lib_session_deinit(handle);
+ hdcp_lib_library_unload(handle);
+
+ cdata.context = handle->client_ctx;
+ cdata.cmd = HDCP_WKUP_CMD_STATUS_FAILED;
+
+ if (!atomic_read(&handle->hdcp_off))
+ hdcp_lib_wakeup_client(handle, &cdata);
+
+ atomic_set(&handle->hdcp_off, 1);
+}
+
+static void hdcp_lib_cleanup_work(struct kthread_work *work)
+{
+
+ struct hdcp_lib_handle *handle = container_of(work,
+ struct hdcp_lib_handle,
+ wk_clean);
+
+ hdcp_lib_clean(handle);
+}
+
+static void hdcp_lib_msg_recvd(struct hdcp_lib_handle *handle)
+{
+ int rc = 0;
+ struct hdcp_wakeup_data cdata = { HDCP_WKUP_CMD_INVALID };
+ struct hdcp_rcvd_msg_req *req_buf;
+ struct hdcp_rcvd_msg_rsp *rsp_buf;
+ uint32_t msglen;
+ char *msg = NULL;
+ char msg_name[50];
+ uint32_t message_id_bytes = 0;
+
+ if (!handle || !handle->qseecom_handle ||
+ !handle->qseecom_handle->sbuf) {
+ pr_err("invalid handle\n");
+ return;
+ }
+
+ if (atomic_read(&handle->hdcp_off)) {
+ pr_debug("invalid state, hdcp off\n");
+ return;
+ }
+
+ cdata.context = handle->client_ctx;
+
+ mutex_lock(&handle->msg_lock);
+ msglen = handle->last_msg_recvd_len;
+
+ if (msglen <= 0) {
+ pr_err("invalid msg len\n");
+ mutex_unlock(&handle->msg_lock);
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ /* If the client is DP then allocate extra byte for message ID. */
+ if (handle->device_type == HDCP_TXMTR_DP)
+ message_id_bytes = 1;
+
+ msglen += message_id_bytes;
+
+ msg = kzalloc(msglen, GFP_KERNEL);
+ if (!msg) {
+ mutex_unlock(&handle->msg_lock);
+ rc = -ENOMEM;
+ goto exit;
+ }
+
+ /* copy the message id if needed */
+ if (message_id_bytes)
+ memcpy(msg, &handle->last_msg, message_id_bytes);
+
+ memcpy(msg + message_id_bytes,
+ handle->last_msg_recvd_buf,
+ handle->last_msg_recvd_len);
+
+ mutex_unlock(&handle->msg_lock);
+
+ snprintf(msg_name, sizeof(msg_name), "%s: ",
+ hdcp_lib_message_name((int)msg[0]));
+
+ print_hex_dump(KERN_DEBUG, msg_name,
+ DUMP_PREFIX_NONE, 16, 1, msg, msglen, false);
+
+ /* send the message to QSEECOM */
+ req_buf = (struct hdcp_rcvd_msg_req *)(handle->qseecom_handle->sbuf);
+ req_buf->commandid = HDCP_TXMTR_PROCESS_RECEIVED_MESSAGE;
+ memcpy(req_buf->msg, msg, msglen);
+ req_buf->msglen = msglen;
+ req_buf->ctxhandle = handle->tz_ctxhandle;
+
+ rsp_buf =
+ (struct hdcp_rcvd_msg_rsp *)(handle->qseecom_handle->sbuf +
+ QSEECOM_ALIGN(sizeof
+ (struct
+ hdcp_rcvd_msg_req)));
+
+ pr_debug("writing %s to TZ at %dms\n",
+ hdcp_lib_message_name((int)msg[0]), jiffies_to_msecs(jiffies));
+
+ rc = qseecom_send_command(handle->qseecom_handle, req_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp_rcvd_msg_req)),
+ rsp_buf,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp_rcvd_msg_rsp)));
+
+ /* get next message from sink if we receive H PRIME on no store km */
+ if ((msg[0] == AKE_SEND_H_PRIME_MESSAGE_ID) &&
+ handle->no_stored_km_flag) {
+ handle->hdcp_timeout = rsp_buf->timeout;
+
+ cdata.cmd = HDCP_WKUP_CMD_RECV_MESSAGE;
+ cdata.timeout = handle->hdcp_timeout;
+
+ goto exit;
+ }
+
+ if ((msg[0] == REPEATER_AUTH_STREAM_READY_MESSAGE_ID) &&
+ (rc == 0) && (rsp_buf->status == 0)) {
+ pr_debug("Got Auth_Stream_Ready, nothing sent to rx\n");
+
+ if (!handle->authenticated &&
+ !hdcp_lib_enable_encryption(handle)) {
+ handle->authenticated = true;
+
+ cdata.cmd = HDCP_WKUP_CMD_STATUS_SUCCESS;
+ hdcp_lib_wakeup_client(handle, &cdata);
+ }
+
+ cdata.cmd = HDCP_WKUP_CMD_LINK_POLL;
+ goto exit;
+ }
+
+ if ((rc < 0) || (rsp_buf->status != 0) || (rsp_buf->msglen <= 0) ||
+ (rsp_buf->commandid != HDCP_TXMTR_PROCESS_RECEIVED_MESSAGE) ||
+ (rsp_buf->msg == NULL)) {
+ pr_err("qseecom cmd failed with err=%d status=%d\n",
+ rc, rsp_buf->status);
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ pr_debug("recvd %s from TZ at %dms\n",
+ hdcp_lib_message_name((int)rsp_buf->msg[0]),
+ jiffies_to_msecs(jiffies));
+
+ handle->last_msg = (int)rsp_buf->msg[0];
+
+ /* set the flag if response is AKE_No_Stored_km */
+ if (((int)rsp_buf->msg[0] == AKE_NO_STORED_KM_MESSAGE_ID)) {
+ pr_debug("Setting no_stored_km_flag\n");
+ handle->no_stored_km_flag = 1;
+ } else {
+ handle->no_stored_km_flag = 0;
+ }
+
+ /* check if it's a repeater */
+ if ((rsp_buf->msg[0] == SKE_SEND_EKS_MESSAGE_ID) &&
+ (rsp_buf->msglen == SKE_SEND_EKS_MESSAGE_SIZE)) {
+ if ((rsp_buf->flag ==
+ HDCP_TXMTR_SUBSTATE_WAITING_FOR_RECIEVERID_LIST) &&
+ (rsp_buf->timeout > 0))
+ handle->repeater_flag = true;
+ handle->update_stream = true;
+ }
+
+ memset(handle->listener_buf, 0, MAX_TX_MESSAGE_SIZE);
+ memcpy(handle->listener_buf, (unsigned char *)rsp_buf->msg,
+ rsp_buf->msglen);
+ handle->hdcp_timeout = rsp_buf->timeout;
+ handle->msglen = rsp_buf->msglen;
+
+ if (!atomic_read(&handle->hdcp_off))
+ hdcp_lib_send_message(handle);
+exit:
+ kzfree(msg);
+
+ hdcp_lib_wakeup_client(handle, &cdata);
+
+ if (rc && !atomic_read(&handle->hdcp_off))
+ HDCP_LIB_EXECUTE(clean);
+}
+
+static void hdcp_lib_msg_recvd_work(struct kthread_work *work)
+{
+ struct hdcp_lib_handle *handle = container_of(work,
+ struct hdcp_lib_handle,
+ wk_msg_recvd);
+
+ hdcp_lib_msg_recvd(handle);
+}
+
+static void hdcp_lib_wait_work(struct kthread_work *work)
+{
+ u32 timeout;
+ struct hdcp_lib_handle *handle = container_of(work,
+ struct hdcp_lib_handle, wk_wait);
+
+ if (!handle) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ if (atomic_read(&handle->hdcp_off)) {
+ pr_debug("invalid state: hdcp off\n");
+ return;
+ }
+
+ if (handle->hdcp_state & HDCP_STATE_ERROR) {
+ pr_debug("invalid state: hdcp error\n");
+ return;
+ }
+
+ reinit_completion(&handle->poll_wait);
+ timeout = wait_for_completion_timeout(&handle->poll_wait,
+ handle->wait_timeout);
+ if (!timeout) {
+ pr_err("wait timeout\n");
+
+ if (!atomic_read(&handle->hdcp_off))
+ HDCP_LIB_EXECUTE(clean);
+ }
+
+ handle->wait_timeout = 0;
+}
+
+bool hdcp1_check_if_supported_load_app(void)
+{
+ int rc = 0;
+
+ /* start hdcp1 app */
+ if (hdcp1_supported && !hdcp1_handle) {
+ rc = qseecom_start_app(&hdcp1_handle, HDCP1_APP_NAME,
+ QSEECOM_SBUFF_SIZE);
+ if (rc) {
+ pr_err("qseecom_start_app failed %d\n", rc);
+ hdcp1_supported = false;
+ } else {
+ mutex_init(&hdcp1_ta_cmd_lock);
+ }
+ }
+
+ pr_debug("hdcp1 app %s loaded\n",
+ hdcp1_supported ? "successfully" : "not");
+
+ return hdcp1_supported;
+}
+
+/* APIs exposed to all clients */
+int hdcp1_set_keys(uint32_t *aksv_msb, uint32_t *aksv_lsb)
+{
+ int rc = 0;
+ struct hdcp1_key_set_req *key_set_req;
+ struct hdcp1_key_set_rsp *key_set_rsp;
+
+ if (aksv_msb == NULL || aksv_lsb == NULL)
+ return -EINVAL;
+
+ if (!hdcp1_supported || !hdcp1_handle)
+ return -EINVAL;
+
+ /* set keys and request aksv */
+ key_set_req = (struct hdcp1_key_set_req *)hdcp1_handle->sbuf;
+ key_set_req->commandid = HDCP1_SET_KEY_MESSAGE_ID;
+ key_set_rsp = (struct hdcp1_key_set_rsp *)(hdcp1_handle->sbuf +
+ QSEECOM_ALIGN(sizeof(struct hdcp1_key_set_req)));
+ rc = qseecom_send_command(hdcp1_handle, key_set_req,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp1_key_set_req)),
+ key_set_rsp,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp1_key_set_rsp)));
+
+ if (rc < 0) {
+ pr_err("qseecom cmd failed err=%d\n", rc);
+ return -ENOKEY;
+ }
+
+ rc = key_set_rsp->ret;
+ if (rc) {
+ pr_err("set key cmd failed, rsp=%d\n", key_set_rsp->ret);
+ return -ENOKEY;
+ }
+
+ /* copy bytes into msb and lsb */
+ *aksv_msb = key_set_rsp->ksv[0] << 24;
+ *aksv_msb |= key_set_rsp->ksv[1] << 16;
+ *aksv_msb |= key_set_rsp->ksv[2] << 8;
+ *aksv_msb |= key_set_rsp->ksv[3];
+ *aksv_lsb = key_set_rsp->ksv[4] << 24;
+ *aksv_lsb |= key_set_rsp->ksv[5] << 16;
+ *aksv_lsb |= key_set_rsp->ksv[6] << 8;
+ *aksv_lsb |= key_set_rsp->ksv[7];
+
+ return 0;
+}
+
+int hdcp1_set_enc(bool enable)
+{
+ int rc = 0;
+ struct hdcp1_set_enc_req *set_enc_req;
+ struct hdcp1_set_enc_rsp *set_enc_rsp;
+
+ mutex_lock(&hdcp1_ta_cmd_lock);
+
+ if (!hdcp1_supported || !hdcp1_handle) {
+ rc = -EINVAL;
+ goto end;
+ }
+
+ if (hdcp1_enc_enabled == enable) {
+ pr_info("already %s\n", enable ? "enabled" : "disabled");
+ goto end;
+ }
+
+ /* set keys and request aksv */
+ set_enc_req = (struct hdcp1_set_enc_req *)hdcp1_handle->sbuf;
+ set_enc_req->commandid = HDCP1_SET_ENC_MESSAGE_ID;
+ set_enc_req->enable = enable;
+ set_enc_rsp = (struct hdcp1_set_enc_rsp *)(hdcp1_handle->sbuf +
+ QSEECOM_ALIGN(sizeof(struct hdcp1_set_enc_req)));
+ rc = qseecom_send_command(hdcp1_handle, set_enc_req,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp1_set_enc_req)),
+ set_enc_rsp,
+ QSEECOM_ALIGN(sizeof
+ (struct hdcp1_set_enc_rsp)));
+
+ if (rc < 0) {
+ pr_err("qseecom cmd failed err=%d\n", rc);
+ goto end;
+ }
+
+ rc = set_enc_rsp->ret;
+ if (rc) {
+ pr_err("enc cmd failed, rsp=%d\n", set_enc_rsp->ret);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ hdcp1_enc_enabled = enable;
+ pr_info("%s success\n", enable ? "enable" : "disable");
+end:
+ mutex_unlock(&hdcp1_ta_cmd_lock);
+ return rc;
+}
+
+int hdcp_library_register(struct hdcp_register_data *data)
+{
+ int rc = 0;
+ struct hdcp_lib_handle *handle = NULL;
+
+ if (!data) {
+ pr_err("invalid input\n");
+ return -EINVAL;
+ }
+
+ if (!data->txmtr_ops) {
+ pr_err("invalid input: txmtr context\n");
+ return -EINVAL;
+ }
+
+ if (!data->client_ops) {
+ pr_err("invalid input: client_ops\n");
+ return -EINVAL;
+ }
+
+ if (!data->hdcp_ctx) {
+ pr_err("invalid input: hdcp_ctx\n");
+ return -EINVAL;
+ }
+
+ /* populate ops to be called by client */
+ data->txmtr_ops->feature_supported = hdcp_lib_client_feature_supported;
+ data->txmtr_ops->wakeup = hdcp_lib_wakeup_thread;
+
+ handle = kzalloc(sizeof(*handle), GFP_KERNEL);
+ if (!handle) {
+ rc = -ENOMEM;
+ goto unlock;
+ }
+
+ handle->client_ctx = data->client_ctx;
+ handle->client_ops = data->client_ops;
+ handle->hdcp_app_init = NULL;
+ handle->hdcp_txmtr_init = NULL;
+ handle->device_type = data->device_type;
+
+ atomic_set(&handle->hdcp_off, 0);
+
+ mutex_init(&handle->msg_lock);
+ mutex_init(&handle->wakeup_mutex);
+
+ kthread_init_worker(&handle->worker);
+
+ kthread_init_work(&handle->wk_init, hdcp_lib_init_work);
+ kthread_init_work(&handle->wk_msg_sent, hdcp_lib_msg_sent_work);
+ kthread_init_work(&handle->wk_msg_recvd, hdcp_lib_msg_recvd_work);
+ kthread_init_work(&handle->wk_timeout, hdcp_lib_manage_timeout_work);
+ kthread_init_work(&handle->wk_clean, hdcp_lib_cleanup_work);
+ kthread_init_work(&handle->wk_wait, hdcp_lib_wait_work);
+ kthread_init_work(&handle->wk_stream, hdcp_lib_query_stream_work);
+
+ init_completion(&handle->poll_wait);
+
+ handle->listener_buf = kzalloc(MAX_TX_MESSAGE_SIZE, GFP_KERNEL);
+ if (!(handle->listener_buf)) {
+ rc = -ENOMEM;
+ goto error;
+ }
+
+ *data->hdcp_ctx = handle;
+ /* Cache the client ctx to be used later
+ * HDCP driver probe happens earlier than
+ * SDE driver probe hence caching it to
+ * be used later.
+ */
+
+ drv_client_handle = handle;
+ handle->thread = kthread_run(kthread_worker_fn,
+ &handle->worker, "hdcp_tz_lib");
+
+ if (IS_ERR(handle->thread)) {
+ pr_err("unable to start lib thread\n");
+ rc = PTR_ERR(handle->thread);
+ handle->thread = NULL;
+ goto error;
+ }
+
+ return 0;
+error:
+ kzfree(handle->listener_buf);
+ handle->listener_buf = NULL;
+ kzfree(handle);
+ handle = NULL;
+unlock:
+ return rc;
+}
+EXPORT_SYMBOL(hdcp_library_register);
+
+void hdcp_library_deregister(void *phdcpcontext)
+{
+ struct hdcp_lib_handle *handle = phdcpcontext;
+
+ if (!handle)
+ return;
+
+ kthread_stop(handle->thread);
+
+ kzfree(handle->qseecom_handle);
+ kzfree(handle->last_msg_recvd_buf);
+
+ mutex_destroy(&handle->wakeup_mutex);
+
+ kzfree(handle->listener_buf);
+ kzfree(handle);
+}
+EXPORT_SYMBOL(hdcp_library_deregister);
+
+void hdcp1_notify_topology(void)
+{
+ char *envp[4];
+ char *a;
+ char *b;
+
+ if (!hdcp_drv_mgr) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ a = kzalloc(SZ_16, GFP_KERNEL);
+
+ if (!a)
+ return;
+
+ b = kzalloc(SZ_16, GFP_KERNEL);
+
+ if (!b) {
+ kfree(a);
+ return;
+ }
+
+ envp[0] = "HDCP_MGR_EVENT=MSG_READY";
+ envp[1] = a;
+ envp[2] = b;
+ envp[3] = NULL;
+
+ snprintf(envp[1], 16, "%d", (int)DOWN_CHECK_TOPOLOGY);
+ snprintf(envp[2], 16, "%d", (int)HDCP_V1_TX);
+
+ kobject_uevent_env(&hdcp_drv_mgr->device->kobj, KOBJ_CHANGE, envp);
+ kfree(a);
+ kfree(b);
+}
+
+static ssize_t msm_hdcp_1x_sysfs_rda_tp(struct device *dev,
+struct device_attribute *attr, char *buf)
+{
+ ssize_t ret = 0;
+
+ if (!hdcp_drv_mgr) {
+ pr_err("invalid input\n");
+ return -EINVAL;
+ }
+
+ switch (hdcp_drv_mgr->tp_msgid) {
+ case DOWN_CHECK_TOPOLOGY:
+ case DOWN_REQUEST_TOPOLOGY:
+ buf[MSG_ID_IDX] = hdcp_drv_mgr->tp_msgid;
+ buf[RET_CODE_IDX] = HDCP_AUTHED;
+ ret = HEADER_LEN;
+
+ memcpy(buf + HEADER_LEN, &hdcp_drv_mgr->cached_tp,
+ sizeof(struct HDCP_V2V1_MSG_TOPOLOGY));
+
+ ret += sizeof(struct HDCP_V2V1_MSG_TOPOLOGY);
+
+ /* clear the flag once data is read back to user space*/
+ hdcp_drv_mgr->tp_msgid = -1;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static ssize_t msm_hdcp_1x_sysfs_wta_tp(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int msgid = 0;
+ ssize_t ret = count;
+
+ if (!hdcp_drv_mgr || !buf) {
+ pr_err("invalid input\n");
+ return -EINVAL;
+ }
+
+ msgid = buf[0];
+
+ switch (msgid) {
+ case DOWN_CHECK_TOPOLOGY:
+ case DOWN_REQUEST_TOPOLOGY:
+ hdcp_drv_mgr->tp_msgid = msgid;
+ break;
+ /* more cases added here */
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static ssize_t hdcp2p2_sysfs_wta_min_level_change(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int rc;
+ int min_enc_lvl;
+ struct hdcp_lib_handle *handle;
+ ssize_t ret = count;
+
+ if (!hdcp_drv_mgr) {
+ pr_err("invalid input\n");
+ return -EINVAL;
+ }
+
+ handle = hdcp_drv_mgr->handle;
+
+ rc = kstrtoint(buf, 10, &min_enc_lvl);
+ if (rc) {
+ pr_err("%s: kstrtoint failed. rc=%d\n", __func__, rc);
+ return -EINVAL;
+ }
+
+ if (handle && handle->client_ops->notify_lvl_change) {
+ handle->client_ops->notify_lvl_change(handle->client_ctx,
+ min_enc_lvl);
+ }
+
+ return ret;
+}
+
+static DEVICE_ATTR(tp, 0644, msm_hdcp_1x_sysfs_rda_tp,
+ msm_hdcp_1x_sysfs_wta_tp);
+
+static DEVICE_ATTR(min_level_change, 0200, NULL,
+ hdcp2p2_sysfs_wta_min_level_change);
+
+void hdcp1_cache_repeater_topology(void *hdcp1_cached_tp)
+{
+ if (!hdcp_drv_mgr) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ memcpy((void *)&hdcp_drv_mgr->cached_tp,
+ hdcp1_cached_tp,
+ sizeof(struct HDCP_V2V1_MSG_TOPOLOGY));
+}
+
+static struct attribute *msm_hdcp_fs_attrs[] = {
+ &dev_attr_tp.attr,
+ &dev_attr_min_level_change.attr,
+ NULL
+};
+
+static struct attribute_group msm_hdcp_fs_attr_group = {
+ .attrs = msm_hdcp_fs_attrs
+};
+
+static int msm_hdcp_open(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static int msm_hdcp_close(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static const struct file_operations msm_hdcp_fops = {
+ .owner = THIS_MODULE,
+ .open = msm_hdcp_open,
+ .release = msm_hdcp_close,
+};
+
+static const struct of_device_id msm_hdcp_dt_match[] = {
+ { .compatible = "qcom,msm-hdcp",},
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, msm_hdcp_dt_match);
+
+static int msm_hdcp_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ hdcp_drv_mgr = devm_kzalloc(&pdev->dev, sizeof(struct msm_hdcp_mgr),
+ GFP_KERNEL);
+ if (!hdcp_drv_mgr)
+ return -ENOMEM;
+
+ hdcp_drv_mgr->pdev = pdev;
+
+ platform_set_drvdata(pdev, hdcp_drv_mgr);
+
+ ret = alloc_chrdev_region(&hdcp_drv_mgr->dev_num, 0, 1, DRIVER_NAME);
+ if (ret < 0) {
+ pr_err("alloc_chrdev_region failed ret = %d\n", ret);
+ goto error_get_dev_num;
+ }
+
+ hdcp_drv_mgr->class = class_create(THIS_MODULE, CLASS_NAME);
+ if (IS_ERR(hdcp_drv_mgr->class)) {
+ ret = PTR_ERR(hdcp_drv_mgr->class);
+ pr_err("couldn't create class rc = %d\n", ret);
+ goto error_class_create;
+ }
+
+ hdcp_drv_mgr->device = device_create(hdcp_drv_mgr->class, NULL,
+ hdcp_drv_mgr->dev_num, NULL, DRIVER_NAME);
+ if (IS_ERR(hdcp_drv_mgr->device)) {
+ ret = PTR_ERR(hdcp_drv_mgr->device);
+ pr_err("device_create failed %d\n", ret);
+ goto error_class_device_create;
+ }
+
+ cdev_init(&hdcp_drv_mgr->cdev, &msm_hdcp_fops);
+ ret = cdev_add(&hdcp_drv_mgr->cdev,
+ MKDEV(MAJOR(hdcp_drv_mgr->dev_num), 0), 1);
+ if (ret < 0) {
+ pr_err("cdev_add failed %d\n", ret);
+ goto error_cdev_add;
+ }
+
+ ret = sysfs_create_group(&hdcp_drv_mgr->device->kobj,
+ &msm_hdcp_fs_attr_group);
+ if (ret)
+ pr_err("unable to register rotator sysfs nodes\n");
+
+ /* Store the handle in the hdcp drv mgr
+ * to be used for the sysfs notifications
+ */
+ hdcp_drv_mgr->handle = drv_client_handle;
+
+ return 0;
+error_cdev_add:
+ device_destroy(hdcp_drv_mgr->class, hdcp_drv_mgr->dev_num);
+error_class_device_create:
+ class_destroy(hdcp_drv_mgr->class);
+error_class_create:
+ unregister_chrdev_region(hdcp_drv_mgr->dev_num, 1);
+error_get_dev_num:
+ devm_kfree(&pdev->dev, hdcp_drv_mgr);
+ hdcp_drv_mgr = NULL;
+ return ret;
+}
+
+static int msm_hdcp_remove(struct platform_device *pdev)
+{
+ struct msm_hdcp_mgr *mgr;
+
+ mgr = (struct msm_hdcp_mgr *)platform_get_drvdata(pdev);
+ if (!mgr)
+ return -ENODEV;
+
+ sysfs_remove_group(&hdcp_drv_mgr->device->kobj,
+ &msm_hdcp_fs_attr_group);
+ cdev_del(&hdcp_drv_mgr->cdev);
+ device_destroy(hdcp_drv_mgr->class, hdcp_drv_mgr->dev_num);
+ class_destroy(hdcp_drv_mgr->class);
+ unregister_chrdev_region(hdcp_drv_mgr->dev_num, 1);
+
+ devm_kfree(&pdev->dev, hdcp_drv_mgr);
+ hdcp_drv_mgr = NULL;
+ return 0;
+}
+
+static struct platform_driver msm_hdcp_driver = {
+ .probe = msm_hdcp_probe,
+ .remove = msm_hdcp_remove,
+ .driver = {
+ .name = "msm_hdcp",
+ .of_match_table = msm_hdcp_dt_match,
+ .pm = NULL,
+ }
+};
+
+static int __init msm_hdcp_init(void)
+{
+ return platform_driver_register(&msm_hdcp_driver);
+}
+
+static void __exit msm_hdcp_exit(void)
+{
+ return platform_driver_unregister(&msm_hdcp_driver);
+}
+
+module_init(msm_hdcp_init);
+module_exit(msm_hdcp_exit);
+
+MODULE_DESCRIPTION("MSM HDCP driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c
index 80f6e57..2f927bd 100644
--- a/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c
+++ b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c
@@ -26,11 +26,14 @@
#include <linux/debugfs.h>
#include <linux/msm_audio_ion.h>
#include <linux/compat.h>
+#include <linux/mutex.h>
#include "audio_utils_aio.h"
#ifdef CONFIG_USE_DEV_CTRL_VOLUME
#include <linux/qdsp6v2/audio_dev_ctl.h>
#endif /*CONFIG_USE_DEV_CTRL_VOLUME*/
+static DEFINE_MUTEX(lock);
#ifdef CONFIG_DEBUG_FS
+
int audio_aio_debug_open(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
@@ -43,29 +46,37 @@
const int debug_bufmax = 4096;
static char buffer[4096];
int n = 0;
- struct q6audio_aio *audio = file->private_data;
+ struct q6audio_aio *audio;
- mutex_lock(&audio->lock);
- n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
- n += scnprintf(buffer + n, debug_bufmax - n,
- "enabled %d\n", audio->enabled);
- n += scnprintf(buffer + n, debug_bufmax - n,
- "stopped %d\n", audio->stopped);
- n += scnprintf(buffer + n, debug_bufmax - n,
- "feedback %d\n", audio->feedback);
- mutex_unlock(&audio->lock);
- /* Following variables are only useful for debugging when
- * when playback halts unexpectedly. Thus, no mutual exclusion
- * enforced
- */
- n += scnprintf(buffer + n, debug_bufmax - n,
- "wflush %d\n", audio->wflush);
- n += scnprintf(buffer + n, debug_bufmax - n,
- "rflush %d\n", audio->rflush);
- n += scnprintf(buffer + n, debug_bufmax - n,
- "inqueue empty %d\n", list_empty(&audio->in_queue));
- n += scnprintf(buffer + n, debug_bufmax - n,
- "outqueue empty %d\n", list_empty(&audio->out_queue));
+ mutex_lock(&lock);
+ if (file->private_data != NULL) {
+ audio = file->private_data;
+ mutex_lock(&audio->lock);
+ n = scnprintf(buffer, debug_bufmax, "opened %d\n",
+ audio->opened);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "enabled %d\n", audio->enabled);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "stopped %d\n", audio->stopped);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "feedback %d\n", audio->feedback);
+ mutex_unlock(&audio->lock);
+ /* Following variables are only useful for debugging when
+ * when playback halts unexpectedly. Thus, no mutual exclusion
+ * enforced
+ */
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "wflush %d\n", audio->wflush);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "rflush %d\n", audio->rflush);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "inqueue empty %d\n",
+ list_empty(&audio->in_queue));
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "outqueue empty %d\n",
+ list_empty(&audio->out_queue));
+ }
+ mutex_unlock(&lock);
buffer[n] = 0;
return simple_read_from_buffer(buf, count, ppos, buffer, n);
}
@@ -580,6 +591,7 @@
struct q6audio_aio *audio = file->private_data;
pr_debug("%s[%pK]\n", __func__, audio);
+ mutex_lock(&lock);
mutex_lock(&audio->lock);
mutex_lock(&audio->read_lock);
mutex_lock(&audio->write_lock);
@@ -622,6 +634,8 @@
#endif
kfree(audio->codec_cfg);
kfree(audio);
+ file->private_data = NULL;
+ mutex_unlock(&lock);
return 0;
}
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 3184dcd..409718b 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -2944,6 +2944,7 @@
return -EBUSY;
}
+ MMC_TRACE(host, "%s\n", __func__);
err = _mmc_suspend(host, true);
if (err)
pr_err("%s: error %d doing aggressive suspend\n",
@@ -2962,6 +2963,7 @@
int err;
ktime_t start = ktime_get();
+ MMC_TRACE(host, "%s\n", __func__);
err = _mmc_resume(host);
if (err && err != -ENOMEDIUM)
pr_err("%s: error %d doing runtime resume\n",
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 4b45ea5..1e25b31 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -2492,15 +2492,31 @@
struct sdhci_msm_host *msm_host = pltfm_host->priv;
const struct sdhci_msm_offset *msm_host_offset =
msm_host->offset;
+ unsigned int irq_flags = 0;
+ struct irq_desc *pwr_irq_desc = irq_to_desc(msm_host->pwr_irq);
- pr_err("%s: PWRCTL_STATUS: 0x%08x | PWRCTL_MASK: 0x%08x | PWRCTL_CTL: 0x%08x\n",
+ if (pwr_irq_desc)
+ irq_flags = ACCESS_PRIVATE(pwr_irq_desc->irq_data.common,
+ state_use_accessors);
+
+ pr_err("%s: PWRCTL_STATUS: 0x%08x | PWRCTL_MASK: 0x%08x | PWRCTL_CTL: 0x%08x, pwr isr state=0x%x\n",
mmc_hostname(host->mmc),
sdhci_msm_readl_relaxed(host,
msm_host_offset->CORE_PWRCTL_STATUS),
sdhci_msm_readl_relaxed(host,
msm_host_offset->CORE_PWRCTL_MASK),
sdhci_msm_readl_relaxed(host,
- msm_host_offset->CORE_PWRCTL_CTL));
+ msm_host_offset->CORE_PWRCTL_CTL), irq_flags);
+
+ MMC_TRACE(host->mmc,
+ "%s: Sts: 0x%08x | Mask: 0x%08x | Ctrl: 0x%08x, pwr isr state=0x%x\n",
+ __func__,
+ sdhci_msm_readb_relaxed(host,
+ msm_host_offset->CORE_PWRCTL_STATUS),
+ sdhci_msm_readb_relaxed(host,
+ msm_host_offset->CORE_PWRCTL_MASK),
+ sdhci_msm_readb_relaxed(host,
+ msm_host_offset->CORE_PWRCTL_CTL), irq_flags);
}
static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data)
@@ -2772,10 +2788,14 @@
if (done)
init_completion(&msm_host->pwr_irq_completion);
else if (!wait_for_completion_timeout(&msm_host->pwr_irq_completion,
- msecs_to_jiffies(MSM_PWR_IRQ_TIMEOUT_MS)))
+ msecs_to_jiffies(MSM_PWR_IRQ_TIMEOUT_MS))) {
__WARN_printf("%s: request(%d) timed out waiting for pwr_irq\n",
mmc_hostname(host->mmc), req_type);
-
+ MMC_TRACE(host->mmc,
+ "%s: request(%d) timed out waiting for pwr_irq\n",
+ __func__, req_type);
+ sdhci_msm_dump_pwr_ctrl_regs(host);
+ }
pr_debug("%s: %s: request %d done\n", mmc_hostname(host->mmc),
__func__, req_type);
}
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 3eada3b..68e49bb 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -245,6 +245,8 @@
if (timeout == 0) {
pr_err("%s: Reset 0x%x never completed.\n",
mmc_hostname(host->mmc), (int)mask);
+ MMC_TRACE(host->mmc, "%s: Reset 0x%x never completed\n",
+ __func__, (int)mask);
if ((host->quirks2 & SDHCI_QUIRK2_USE_RESET_WORKAROUND)
&& host->ops->reset_workaround) {
if (!host->reset_wa_applied) {
@@ -1244,6 +1246,9 @@
if (timeout == 0) {
pr_err("%s: Controller never released inhibit bit(s).\n",
mmc_hostname(host->mmc));
+ MMC_TRACE(host->mmc,
+ "%s :Controller never released inhibit bit(s)\n",
+ __func__);
sdhci_dumpregs(host);
cmd->error = -EIO;
sdhci_finish_mrq(host, cmd->mrq);
@@ -1302,12 +1307,12 @@
if (cmd->data)
host->data_start_time = ktime_get();
trace_mmc_cmd_rw_start(cmd->opcode, cmd->arg, cmd->flags);
+ sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
MMC_TRACE(host->mmc,
"%s: updated 0x8=0x%08x 0xC=0x%08x 0xE=0x%08x\n", __func__,
sdhci_readl(host, SDHCI_ARGUMENT),
sdhci_readw(host, SDHCI_TRANSFER_MODE),
sdhci_readw(host, SDHCI_COMMAND));
- sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
}
EXPORT_SYMBOL_GPL(sdhci_send_command);
@@ -1533,6 +1538,8 @@
if (timeout == 0) {
pr_err("%s: Internal clock never stabilised.\n",
mmc_hostname(host->mmc));
+ MMC_TRACE(host->mmc,
+ "%s: Internal clock never stabilised.\n", __func__);
sdhci_dumpregs(host);
return;
}
@@ -2917,6 +2924,7 @@
(host->cmd && sdhci_data_line_cmd(host->cmd))) {
pr_err("%s: Timeout waiting for hardware interrupt.\n",
mmc_hostname(host->mmc));
+ MMC_TRACE(host->mmc, "Timeout waiting for h/w interrupt\n");
sdhci_dumpregs(host);
if (host->data) {
@@ -2959,6 +2967,9 @@
return;
pr_err("%s: Got command interrupt 0x%08x even though no command operation was in progress.\n",
mmc_hostname(host->mmc), (unsigned)intmask);
+ MMC_TRACE(host->mmc,
+ "Got command interrupt 0x%08x even though no command operation was in progress.\n",
+ (unsigned int)intmask);
sdhci_dumpregs(host);
return;
}
@@ -3111,6 +3122,9 @@
pr_err("%s: Got data interrupt 0x%08x even though no data operation was in progress.\n",
mmc_hostname(host->mmc), (unsigned)intmask);
+ MMC_TRACE(host->mmc,
+ "Got data interrupt 0x%08x even though no data operation was in progress.\n",
+ (unsigned int)intmask);
sdhci_dumpregs(host);
return;
@@ -3146,6 +3160,11 @@
mmc_hostname(host->mmc), intmask,
host->data->error, ktime_to_ms(ktime_sub(
ktime_get(), host->data_start_time)));
+ MMC_TRACE(host->mmc,
+ "data txfr (0x%08x) error: %d after %lld ms\n",
+ intmask, host->data->error,
+ ktime_to_ms(ktime_sub(ktime_get(),
+ host->data_start_time)));
if (!host->mmc->sdr104_wa ||
(host->mmc->ios.timing != MMC_TIMING_UHS_SDR104))
@@ -3399,6 +3418,8 @@
if (unexpected) {
pr_err("%s: Unexpected interrupt 0x%08x.\n",
mmc_hostname(host->mmc), unexpected);
+ MMC_TRACE(host->mmc, "Unexpected interrupt 0x%08x.\n",
+ unexpected);
sdhci_dumpregs(host);
}
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c
index db15141..c6a5d29 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.c
+++ b/drivers/pinctrl/qcom/pinctrl-msm.c
@@ -40,6 +40,7 @@
#define MAX_NR_GPIO 300
#define PS_HOLD_OFFSET 0x820
+#define STATUS_OFFSET 0x10
/**
* struct msm_pinctrl - state for a pinctrl-msm device
@@ -74,6 +75,35 @@
static struct msm_pinctrl *msm_pinctrl_data;
+static u32 msm_pinctrl_find_base(const struct msm_pinctrl_soc_data *soc_data,
+ u32 gpio_id)
+{
+ int i;
+ u32 val;
+
+ if (gpio_id >= soc_data->ngpios || !soc_data->pin_base)
+ return 0;
+
+ if (soc_data->pin_base[gpio_id])
+ return soc_data->pin_base[gpio_id];
+
+ for (i = 0; i < soc_data->n_tile_offsets; i++) {
+ val = readl_relaxed(msm_pinctrl_data->regs +
+ soc_data->tile_offsets[i] + STATUS_OFFSET
+ + soc_data->reg_size * gpio_id);
+ if (val) {
+ soc_data->pin_base[gpio_id] = soc_data->tile_offsets[i];
+ return soc_data->tile_offsets[i];
+ }
+ }
+
+ /* In the case that the soc_data does not support dynamic base
+ * detection, we return 0 here.
+ */
+ WARN_ONCE(1, "%s:Dynamic base detection is not supported\n", __func__);
+ return 0;
+}
+
static int msm_get_groups_count(struct pinctrl_dev *pctldev)
{
struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
@@ -143,10 +173,11 @@
struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
const struct msm_pingroup *g;
unsigned long flags;
- u32 val, mask;
+ u32 val, mask, base;
int i;
g = &pctrl->soc->groups[group];
+ base = msm_pinctrl_find_base(pctrl->soc, group);
mask = GENMASK(g->mux_bit + order_base_2(g->nfuncs) - 1, g->mux_bit);
for (i = 0; i < g->nfuncs; i++) {
@@ -159,10 +190,10 @@
spin_lock_irqsave(&pctrl->lock, flags);
- val = readl(pctrl->regs + g->ctl_reg);
+ val = readl(pctrl->regs + base + g->ctl_reg);
val &= ~mask;
val |= i << g->mux_bit;
- writel(val, pctrl->regs + g->ctl_reg);
+ writel(val, pctrl->regs + base + g->ctl_reg);
spin_unlock_irqrestore(&pctrl->lock, flags);
@@ -227,15 +258,16 @@
unsigned arg;
unsigned bit;
int ret;
- u32 val;
+ u32 val, base;
g = &pctrl->soc->groups[group];
+ base = msm_pinctrl_find_base(pctrl->soc, group);
ret = msm_config_reg(pctrl, g, param, &mask, &bit);
if (ret < 0)
return ret;
- val = readl(pctrl->regs + g->ctl_reg);
+ val = readl(pctrl->regs + base + g->ctl_reg);
arg = (val >> bit) & mask;
/* Convert register value to pinconf value */
@@ -260,7 +292,7 @@
if (!arg)
return -EINVAL;
- val = readl(pctrl->regs + g->io_reg);
+ val = readl(pctrl->regs + base + g->io_reg);
arg = !!(val & BIT(g->in_bit));
break;
case PIN_CONFIG_INPUT_ENABLE:
@@ -291,11 +323,12 @@
unsigned arg;
unsigned bit;
int ret;
- u32 val;
+ u32 val, base;
int i;
g = &pctrl->soc->groups[group];
+ base = msm_pinctrl_find_base(pctrl->soc, group);
for (i = 0; i < num_configs; i++) {
param = pinconf_to_config_param(configs[i]);
arg = pinconf_to_config_argument(configs[i]);
@@ -328,12 +361,12 @@
case PIN_CONFIG_OUTPUT:
/* set output value */
spin_lock_irqsave(&pctrl->lock, flags);
- val = readl(pctrl->regs + g->io_reg);
+ val = readl(pctrl->regs + base + g->io_reg);
if (arg)
val |= BIT(g->out_bit);
else
val &= ~BIT(g->out_bit);
- writel(val, pctrl->regs + g->io_reg);
+ writel(val, pctrl->regs + base + g->io_reg);
spin_unlock_irqrestore(&pctrl->lock, flags);
/* enable output */
@@ -356,10 +389,10 @@
}
spin_lock_irqsave(&pctrl->lock, flags);
- val = readl(pctrl->regs + g->ctl_reg);
+ val = readl(pctrl->regs + base + g->ctl_reg);
val &= ~(mask << bit);
val |= arg << bit;
- writel(val, pctrl->regs + g->ctl_reg);
+ writel(val, pctrl->regs + base + g->ctl_reg);
spin_unlock_irqrestore(&pctrl->lock, flags);
}
@@ -384,15 +417,16 @@
const struct msm_pingroup *g;
struct msm_pinctrl *pctrl = gpiochip_get_data(chip);
unsigned long flags;
- u32 val;
+ u32 val, base;
g = &pctrl->soc->groups[offset];
+ base = msm_pinctrl_find_base(pctrl->soc, offset);
spin_lock_irqsave(&pctrl->lock, flags);
- val = readl(pctrl->regs + g->ctl_reg);
+ val = readl(pctrl->regs + base + g->ctl_reg);
val &= ~BIT(g->oe_bit);
- writel(val, pctrl->regs + g->ctl_reg);
+ writel(val, pctrl->regs + base + g->ctl_reg);
spin_unlock_irqrestore(&pctrl->lock, flags);
@@ -404,22 +438,23 @@
const struct msm_pingroup *g;
struct msm_pinctrl *pctrl = gpiochip_get_data(chip);
unsigned long flags;
- u32 val;
+ u32 val, base;
g = &pctrl->soc->groups[offset];
+ base = msm_pinctrl_find_base(pctrl->soc, offset);
spin_lock_irqsave(&pctrl->lock, flags);
- val = readl(pctrl->regs + g->io_reg);
+ val = readl(pctrl->regs + base + g->io_reg);
if (value)
val |= BIT(g->out_bit);
else
val &= ~BIT(g->out_bit);
- writel(val, pctrl->regs + g->io_reg);
+ writel(val, pctrl->regs + base + g->io_reg);
- val = readl(pctrl->regs + g->ctl_reg);
+ val = readl(pctrl->regs + base + g->ctl_reg);
val |= BIT(g->oe_bit);
- writel(val, pctrl->regs + g->ctl_reg);
+ writel(val, pctrl->regs + base + g->ctl_reg);
spin_unlock_irqrestore(&pctrl->lock, flags);
@@ -430,11 +465,12 @@
{
const struct msm_pingroup *g;
struct msm_pinctrl *pctrl = gpiochip_get_data(chip);
- u32 val;
+ u32 val, base;
g = &pctrl->soc->groups[offset];
+ base = msm_pinctrl_find_base(pctrl->soc, offset);
- val = readl(pctrl->regs + g->io_reg);
+ val = readl(pctrl->regs + base + g->io_reg);
return !!(val & BIT(g->in_bit));
}
@@ -443,18 +479,19 @@
const struct msm_pingroup *g;
struct msm_pinctrl *pctrl = gpiochip_get_data(chip);
unsigned long flags;
- u32 val;
+ u32 val, base;
g = &pctrl->soc->groups[offset];
+ base = msm_pinctrl_find_base(pctrl->soc, offset);
spin_lock_irqsave(&pctrl->lock, flags);
- val = readl(pctrl->regs + g->io_reg);
+ val = readl(pctrl->regs + base + g->io_reg);
if (value)
val |= BIT(g->out_bit);
else
val &= ~BIT(g->out_bit);
- writel(val, pctrl->regs + g->io_reg);
+ writel(val, pctrl->regs + base + g->io_reg);
spin_unlock_irqrestore(&pctrl->lock, flags);
}
@@ -474,7 +511,7 @@
int is_out;
int drive;
int pull;
- u32 ctl_reg;
+ u32 ctl_reg, base;
static const char * const pulls[] = {
"no pull",
@@ -484,7 +521,9 @@
};
g = &pctrl->soc->groups[offset];
- ctl_reg = readl(pctrl->regs + g->ctl_reg);
+ base = msm_pinctrl_find_base(pctrl->soc, offset);
+
+ ctl_reg = readl(pctrl->regs + base + g->ctl_reg);
is_out = !!(ctl_reg & BIT(g->oe_bit));
func = (ctl_reg >> g->mux_bit) & 7;
@@ -543,21 +582,21 @@
*/
static void msm_gpio_update_dual_edge_pos(struct msm_pinctrl *pctrl,
const struct msm_pingroup *g,
- struct irq_data *d)
+ struct irq_data *d, u32 base)
{
int loop_limit = 100;
unsigned val, val2, intstat;
unsigned pol;
do {
- val = readl(pctrl->regs + g->io_reg) & BIT(g->in_bit);
+ val = readl(pctrl->regs + base + g->io_reg) & BIT(g->in_bit);
- pol = readl(pctrl->regs + g->intr_cfg_reg);
+ pol = readl(pctrl->regs + base + g->intr_cfg_reg);
pol ^= BIT(g->intr_polarity_bit);
- writel(pol, pctrl->regs + g->intr_cfg_reg);
+ writel(pol, pctrl->regs + base + g->intr_cfg_reg);
- val2 = readl(pctrl->regs + g->io_reg) & BIT(g->in_bit);
- intstat = readl(pctrl->regs + g->intr_status_reg);
+ val2 = readl(pctrl->regs + base + g->io_reg) & BIT(g->in_bit);
+ intstat = readl(pctrl->regs + base + g->intr_status_reg);
if (intstat || (val == val2))
return;
} while (loop_limit-- > 0);
@@ -571,15 +610,16 @@
struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
const struct msm_pingroup *g;
unsigned long flags;
- u32 val;
+ u32 val, base;
g = &pctrl->soc->groups[d->hwirq];
+ base = msm_pinctrl_find_base(pctrl->soc, d->hwirq);
spin_lock_irqsave(&pctrl->lock, flags);
- val = readl(pctrl->regs + g->intr_cfg_reg);
+ val = readl(pctrl->regs + base + g->intr_cfg_reg);
val &= ~BIT(g->intr_enable_bit);
- writel(val, pctrl->regs + g->intr_cfg_reg);
+ writel(val, pctrl->regs + base + g->intr_cfg_reg);
clear_bit(d->hwirq, pctrl->enabled_irqs);
@@ -592,15 +632,16 @@
struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
const struct msm_pingroup *g;
unsigned long flags;
- u32 val;
+ u32 val, base;
g = &pctrl->soc->groups[d->hwirq];
+ base = msm_pinctrl_find_base(pctrl->soc, d->hwirq);
spin_lock_irqsave(&pctrl->lock, flags);
- val = readl(pctrl->regs + g->intr_cfg_reg);
+ val = readl(pctrl->regs + base + g->intr_cfg_reg);
val |= BIT(g->intr_enable_bit);
- writel(val, pctrl->regs + g->intr_cfg_reg);
+ writel(val, pctrl->regs + base + g->intr_cfg_reg);
set_bit(d->hwirq, pctrl->enabled_irqs);
@@ -613,21 +654,22 @@
struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
const struct msm_pingroup *g;
unsigned long flags;
- u32 val;
+ u32 val, base;
g = &pctrl->soc->groups[d->hwirq];
+ base = msm_pinctrl_find_base(pctrl->soc, d->hwirq);
spin_lock_irqsave(&pctrl->lock, flags);
- val = readl(pctrl->regs + g->intr_status_reg);
+ val = readl(pctrl->regs + base + g->intr_status_reg);
if (g->intr_ack_high)
val |= BIT(g->intr_status_bit);
else
val &= ~BIT(g->intr_status_bit);
- writel(val, pctrl->regs + g->intr_status_reg);
+ writel(val, pctrl->regs + base + g->intr_status_reg);
if (test_bit(d->hwirq, pctrl->dual_edge_irqs))
- msm_gpio_update_dual_edge_pos(pctrl, g, d);
+ msm_gpio_update_dual_edge_pos(pctrl, g, d, base);
spin_unlock_irqrestore(&pctrl->lock, flags);
}
@@ -638,10 +680,10 @@
struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
const struct msm_pingroup *g;
unsigned long flags;
- u32 val;
+ u32 val, base;
g = &pctrl->soc->groups[d->hwirq];
-
+ base = msm_pinctrl_find_base(pctrl->soc, d->hwirq);
spin_lock_irqsave(&pctrl->lock, flags);
/*
@@ -653,17 +695,17 @@
clear_bit(d->hwirq, pctrl->dual_edge_irqs);
/* Route interrupts to application cpu */
- val = readl(pctrl->regs + g->intr_target_reg);
+ val = readl(pctrl->regs + base + g->intr_target_reg);
val &= ~(7 << g->intr_target_bit);
val |= g->intr_target_kpss_val << g->intr_target_bit;
- writel(val, pctrl->regs + g->intr_target_reg);
+ writel(val, pctrl->regs + base + g->intr_target_reg);
/* Update configuration for gpio.
* RAW_STATUS_EN is left on for all gpio irqs. Due to the
* internal circuitry of TLMM, toggling the RAW_STATUS
* could cause the INTR_STATUS to be set for EDGE interrupts.
*/
- val = readl(pctrl->regs + g->intr_cfg_reg);
+ val = readl(pctrl->regs + base + g->intr_cfg_reg);
val |= BIT(g->intr_raw_status_bit);
if (g->intr_detection_width == 2) {
val &= ~(3 << g->intr_detection_bit);
@@ -711,10 +753,10 @@
} else {
BUG();
}
- writel(val, pctrl->regs + g->intr_cfg_reg);
+ writel(val, pctrl->regs + base + g->intr_cfg_reg);
if (test_bit(d->hwirq, pctrl->dual_edge_irqs))
- msm_gpio_update_dual_edge_pos(pctrl, g, d);
+ msm_gpio_update_dual_edge_pos(pctrl, g, d, base);
spin_unlock_irqrestore(&pctrl->lock, flags);
@@ -843,7 +885,7 @@
struct irq_chip *chip = irq_desc_get_chip(desc);
int irq_pin;
int handled = 0;
- u32 val;
+ u32 val, base;
int i;
chained_irq_enter(chip, desc);
@@ -854,7 +896,8 @@
*/
for_each_set_bit(i, pctrl->enabled_irqs, pctrl->chip.ngpio) {
g = &pctrl->soc->groups[i];
- val = readl(pctrl->regs + g->intr_status_reg);
+ base = msm_pinctrl_find_base(pctrl->soc, i);
+ val = readl(pctrl->regs + base + g->intr_status_reg);
if (val & BIT(g->intr_status_bit)) {
irq_pin = irq_find_mapping(gc->irqdomain, i);
generic_handle_irq(irq_pin);
@@ -1016,6 +1059,7 @@
const struct msm_pingroup *g;
const char *name = "null";
struct msm_pinctrl *pctrl = msm_pinctrl_data;
+ u32 base;
if (!msm_show_resume_irq_mask)
return;
@@ -1023,7 +1067,8 @@
spin_lock_irqsave(&pctrl->lock, flags);
for_each_set_bit(i, pctrl->enabled_irqs, pctrl->chip.ngpio) {
g = &pctrl->soc->groups[i];
- val = readl_relaxed(pctrl->regs + g->intr_status_reg);
+ base = msm_pinctrl_find_base(pctrl->soc, i);
+ val = readl_relaxed(pctrl->regs + base + g->intr_status_reg);
if (val & BIT(g->intr_status_bit)) {
irq = irq_find_mapping(pctrl->chip.irqdomain, i);
desc = irq_to_desc(irq);
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.h b/drivers/pinctrl/qcom/pinctrl-msm.h
index 0e223e0..375a962 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.h
+++ b/drivers/pinctrl/qcom/pinctrl-msm.h
@@ -129,6 +129,10 @@
unsigned ngpios;
const struct msm_dir_conn *dir_conn;
unsigned int n_dir_conns;
+ const u32 *tile_offsets;
+ unsigned int n_tile_offsets;
+ u32 *pin_base;
+ unsigned int reg_size;
};
int msm_pinctrl_probe(struct platform_device *pdev,
diff --git a/drivers/pinctrl/qcom/pinctrl-sdm670.c b/drivers/pinctrl/qcom/pinctrl-sdm670.c
index 1f742f8..4334779 100644
--- a/drivers/pinctrl/qcom/pinctrl-sdm670.c
+++ b/drivers/pinctrl/qcom/pinctrl-sdm670.c
@@ -25,12 +25,8 @@
.ngroups = ARRAY_SIZE(fname##_groups), \
}
-#define NORTH 0x00500000
-#define SOUTH 0x00900000
-#define WEST 0x00100000
-#define DUMMY 0x0
#define REG_SIZE 0x1000
-#define PINGROUP(id, base, f1, f2, f3, f4, f5, f6, f7, f8, f9) \
+#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9) \
{ \
.name = "gpio" #id, \
.pins = gpio##id##_pins, \
@@ -48,11 +44,11 @@
msm_mux_##f9 \
}, \
.nfuncs = 10, \
- .ctl_reg = base + REG_SIZE * id, \
- .io_reg = base + 0x4 + REG_SIZE * id, \
- .intr_cfg_reg = base + 0x8 + REG_SIZE * id, \
- .intr_status_reg = base + 0xc + REG_SIZE * id, \
- .intr_target_reg = base + 0x8 + REG_SIZE * id, \
+ .ctl_reg = REG_SIZE * id, \
+ .io_reg = 0x4 + REG_SIZE * id, \
+ .intr_cfg_reg = 0x8 + REG_SIZE * id, \
+ .intr_status_reg = 0xc + REG_SIZE * id, \
+ .intr_target_reg = 0x8 + REG_SIZE * id, \
.mux_bit = 2, \
.pull_bit = 0, \
.drv_bit = 6, \
@@ -118,6 +114,10 @@
.intr_detection_bit = -1, \
.intr_detection_width = -1, \
}
+
+static const u32 sdm670_tile_offsets[] = {0x100000, 0x500000, 0x900000};
+static u32 sdm670_pin_base[150];
+
static const struct pinctrl_pin_desc sdm670_pins[] = {
PINCTRL_PIN(0, "GPIO_0"),
PINCTRL_PIN(1, "GPIO_1"),
@@ -1332,249 +1332,249 @@
* Clients would not be able to request these dummy pin groups.
*/
static const struct msm_pingroup sdm670_groups[] = {
- [0] = PINGROUP(0, SOUTH, qup0, NA, NA, NA, NA, NA, NA, NA, NA),
- [1] = PINGROUP(1, SOUTH, qup0, NA, NA, NA, NA, NA, NA, NA, NA),
- [2] = PINGROUP(2, SOUTH, qup0, NA, NA, NA, NA, NA, NA, NA, NA),
- [3] = PINGROUP(3, SOUTH, qup0, NA, NA, NA, NA, NA, NA, NA, NA),
- [4] = PINGROUP(4, NORTH, qup9, qdss_cti, NA, NA, NA, NA, NA, NA, NA),
- [5] = PINGROUP(5, NORTH, qup9, qdss_cti, NA, NA, NA, NA, NA, NA, NA),
- [6] = PINGROUP(6, NORTH, qup9, NA, ddr_pxi0, NA, NA, NA, NA, NA, NA),
- [7] = PINGROUP(7, NORTH, qup9, ddr_bist, NA, atest_tsens2,
+ [0] = PINGROUP(0, qup0, NA, NA, NA, NA, NA, NA, NA, NA),
+ [1] = PINGROUP(1, qup0, NA, NA, NA, NA, NA, NA, NA, NA),
+ [2] = PINGROUP(2, qup0, NA, NA, NA, NA, NA, NA, NA, NA),
+ [3] = PINGROUP(3, qup0, NA, NA, NA, NA, NA, NA, NA, NA),
+ [4] = PINGROUP(4, qup9, qdss_cti, NA, NA, NA, NA, NA, NA, NA),
+ [5] = PINGROUP(5, qup9, qdss_cti, NA, NA, NA, NA, NA, NA, NA),
+ [6] = PINGROUP(6, qup9, NA, ddr_pxi0, NA, NA, NA, NA, NA, NA),
+ [7] = PINGROUP(7, qup9, ddr_bist, NA, atest_tsens2,
vsense_trigger, atest_usb1, ddr_pxi0, NA, NA),
- [8] = PINGROUP(8, WEST, qup_l4, GP_PDM1, ddr_bist, NA, NA, NA, NA, NA,
+ [8] = PINGROUP(8, qup_l4, GP_PDM1, ddr_bist, NA, NA, NA, NA, NA,
NA),
- [9] = PINGROUP(9, WEST, qup_l5, ddr_bist, NA, NA, NA, NA, NA, NA, NA),
- [10] = PINGROUP(10, NORTH, mdp_vsync, qup_l6, ddr_bist, wlan2_adc1,
+ [9] = PINGROUP(9, qup_l5, ddr_bist, NA, NA, NA, NA, NA, NA, NA),
+ [10] = PINGROUP(10, mdp_vsync, qup_l6, ddr_bist, wlan2_adc1,
atest_usb11, ddr_pxi2, NA, NA, NA),
- [11] = PINGROUP(11, NORTH, mdp_vsync, edp_lcd, dbg_out, wlan2_adc0,
+ [11] = PINGROUP(11, mdp_vsync, edp_lcd, dbg_out, wlan2_adc0,
atest_usb10, ddr_pxi2, NA, NA, NA),
- [12] = PINGROUP(12, SOUTH, mdp_vsync, m_voc, tsif1_sync, ddr_pxi3, NA,
+ [12] = PINGROUP(12, mdp_vsync, m_voc, tsif1_sync, ddr_pxi3, NA,
NA, NA, NA, NA),
- [13] = PINGROUP(13, WEST, cam_mclk, pll_bypassnl, qdss_gpio0, ddr_pxi3,
+ [13] = PINGROUP(13, cam_mclk, pll_bypassnl, qdss_gpio0, ddr_pxi3,
NA, NA, NA, NA, NA),
- [14] = PINGROUP(14, WEST, cam_mclk, pll_reset, qdss_gpio1, NA, NA, NA,
+ [14] = PINGROUP(14, cam_mclk, pll_reset, qdss_gpio1, NA, NA, NA,
NA, NA, NA),
- [15] = PINGROUP(15, WEST, cam_mclk, qdss_gpio2, NA, NA, NA, NA, NA, NA,
+ [15] = PINGROUP(15, cam_mclk, qdss_gpio2, NA, NA, NA, NA, NA, NA,
NA),
- [16] = PINGROUP(16, WEST, cam_mclk, qdss_gpio3, NA, NA, NA, NA, NA, NA,
+ [16] = PINGROUP(16, cam_mclk, qdss_gpio3, NA, NA, NA, NA, NA, NA,
NA),
- [17] = PINGROUP(17, WEST, cci_i2c, qup1, qdss_gpio4, NA, NA, NA, NA,
+ [17] = PINGROUP(17, cci_i2c, qup1, qdss_gpio4, NA, NA, NA, NA,
NA, NA),
- [18] = PINGROUP(18, WEST, cci_i2c, qup1, NA, qdss_gpio5, NA, NA, NA,
+ [18] = PINGROUP(18, cci_i2c, qup1, NA, qdss_gpio5, NA, NA, NA,
NA, NA),
- [19] = PINGROUP(19, WEST, cci_i2c, qup1, NA, qdss_gpio6, NA, NA, NA,
+ [19] = PINGROUP(19, cci_i2c, qup1, NA, qdss_gpio6, NA, NA, NA,
NA, NA),
- [20] = PINGROUP(20, WEST, cci_i2c, qup1, NA, qdss_gpio7, NA, NA, NA,
+ [20] = PINGROUP(20, cci_i2c, qup1, NA, qdss_gpio7, NA, NA, NA,
NA, NA),
- [21] = PINGROUP(21, WEST, cci_timer0, gcc_gp2, qdss_gpio8, NA, NA, NA,
+ [21] = PINGROUP(21, cci_timer0, gcc_gp2, qdss_gpio8, NA, NA, NA,
NA, NA, NA),
- [22] = PINGROUP(22, WEST, cci_timer1, gcc_gp3, qdss_gpio, NA, NA, NA,
+ [22] = PINGROUP(22, cci_timer1, gcc_gp3, qdss_gpio, NA, NA, NA,
NA, NA, NA),
- [23] = PINGROUP(23, WEST, cci_timer2, qdss_gpio9, NA, NA, NA, NA, NA,
+ [23] = PINGROUP(23, cci_timer2, qdss_gpio9, NA, NA, NA, NA, NA,
NA, NA),
- [24] = PINGROUP(24, WEST, cci_timer3, cci_async, qdss_gpio10, NA, NA,
+ [24] = PINGROUP(24, cci_timer3, cci_async, qdss_gpio10, NA, NA,
NA, NA, NA, NA),
- [25] = PINGROUP(25, WEST, cci_timer4, cci_async, qdss_gpio11, NA, NA,
+ [25] = PINGROUP(25, cci_timer4, cci_async, qdss_gpio11, NA, NA,
NA, NA, NA, NA),
- [26] = PINGROUP(26, WEST, cci_async, qdss_gpio12, JITTER_BIST, NA, NA,
+ [26] = PINGROUP(26, cci_async, qdss_gpio12, JITTER_BIST, NA, NA,
NA, NA, NA, NA),
- [27] = PINGROUP(27, WEST, qup2, qdss_gpio13, PLL_BIST, NA, NA, NA, NA,
+ [27] = PINGROUP(27, qup2, qdss_gpio13, PLL_BIST, NA, NA, NA, NA,
NA, NA),
- [28] = PINGROUP(28, WEST, qup2, qdss_gpio14, AGERA_PLL, NA, NA, NA, NA,
+ [28] = PINGROUP(28, qup2, qdss_gpio14, AGERA_PLL, NA, NA, NA, NA,
NA, NA),
- [29] = PINGROUP(29, WEST, qup2, NA, phase_flag1, qdss_gpio15,
+ [29] = PINGROUP(29, qup2, NA, phase_flag1, qdss_gpio15,
atest_tsens, NA, NA, NA, NA),
- [30] = PINGROUP(30, WEST, qup2, phase_flag2, qdss_gpio, NA, NA, NA, NA,
+ [30] = PINGROUP(30, qup2, phase_flag2, qdss_gpio, NA, NA, NA, NA,
NA, NA),
- [31] = PINGROUP(31, WEST, qup11, qup14, NA, NA, NA, NA, NA, NA, NA),
- [32] = PINGROUP(32, WEST, qup11, qup14, NA, NA, NA, NA, NA, NA, NA),
- [33] = PINGROUP(33, WEST, qup11, qup14, NA, NA, NA, NA, NA, NA, NA),
- [34] = PINGROUP(34, WEST, qup11, qup14, NA, NA, NA, NA, NA, NA, NA),
- [35] = PINGROUP(35, NORTH, pci_e0, QUP_L4, JITTER_BIST, NA, NA, NA, NA,
+ [31] = PINGROUP(31, qup11, qup14, NA, NA, NA, NA, NA, NA, NA),
+ [32] = PINGROUP(32, qup11, qup14, NA, NA, NA, NA, NA, NA, NA),
+ [33] = PINGROUP(33, qup11, qup14, NA, NA, NA, NA, NA, NA, NA),
+ [34] = PINGROUP(34, qup11, qup14, NA, NA, NA, NA, NA, NA, NA),
+ [35] = PINGROUP(35, pci_e0, QUP_L4, JITTER_BIST, NA, NA, NA, NA,
NA, NA),
- [36] = PINGROUP(36, NORTH, pci_e0, QUP_L5, PLL_BIST, NA, NA, NA, NA,
+ [36] = PINGROUP(36, pci_e0, QUP_L5, PLL_BIST, NA, NA, NA, NA,
NA, NA),
- [37] = PINGROUP(37, NORTH, QUP_L6, AGERA_PLL, NA, NA, NA, NA, NA, NA,
+ [37] = PINGROUP(37, QUP_L6, AGERA_PLL, NA, NA, NA, NA, NA, NA,
NA),
- [38] = PINGROUP(38, NORTH, usb_phy, NA, NA, NA, NA, NA, NA, NA, NA),
- [39] = PINGROUP(39, NORTH, lpass_slimbus, NA, NA, NA, NA, NA, NA, NA,
+ [38] = PINGROUP(38, usb_phy, NA, NA, NA, NA, NA, NA, NA, NA),
+ [39] = PINGROUP(39, lpass_slimbus, NA, NA, NA, NA, NA, NA, NA,
NA),
- [40] = PINGROUP(40, NORTH, sd_write, tsif1_error, NA, NA, NA, NA, NA,
+ [40] = PINGROUP(40, sd_write, tsif1_error, NA, NA, NA, NA, NA,
NA, NA),
- [41] = PINGROUP(41, SOUTH, qup3, NA, qdss_gpio6, NA, NA, NA, NA, NA,
+ [41] = PINGROUP(41, qup3, NA, qdss_gpio6, NA, NA, NA, NA, NA,
NA),
- [42] = PINGROUP(42, SOUTH, qup3, NA, qdss_gpio7, NA, NA, NA, NA, NA,
+ [42] = PINGROUP(42, qup3, NA, qdss_gpio7, NA, NA, NA, NA, NA,
NA),
- [43] = PINGROUP(43, SOUTH, qup3, NA, qdss_gpio14, NA, NA, NA, NA, NA,
+ [43] = PINGROUP(43, qup3, NA, qdss_gpio14, NA, NA, NA, NA, NA,
NA),
- [44] = PINGROUP(44, SOUTH, qup3, NA, qdss_gpio15, NA, NA, NA, NA, NA,
+ [44] = PINGROUP(44, qup3, NA, qdss_gpio15, NA, NA, NA, NA, NA,
NA),
- [45] = PINGROUP(45, SOUTH, qup6, NA, NA, NA, NA, NA, NA, NA, NA),
- [46] = PINGROUP(46, SOUTH, qup6, NA, NA, NA, NA, NA, NA, NA, NA),
- [47] = PINGROUP(47, SOUTH, qup6, NA, NA, NA, NA, NA, NA, NA, NA),
- [48] = PINGROUP(48, SOUTH, qup6, NA, NA, NA, NA, NA, NA, NA, NA),
- [49] = PINGROUP(49, NORTH, qup12, NA, NA, NA, NA, NA, NA, NA, NA),
- [50] = PINGROUP(50, NORTH, qup12, NA, NA, NA, NA, NA, NA, NA, NA),
- [51] = PINGROUP(51, NORTH, qup12, qdss_cti, NA, NA, NA, NA, NA, NA, NA),
- [52] = PINGROUP(52, NORTH, qup12, phase_flag16, qdss_cti, NA, NA, NA,
+ [45] = PINGROUP(45, qup6, NA, NA, NA, NA, NA, NA, NA, NA),
+ [46] = PINGROUP(46, qup6, NA, NA, NA, NA, NA, NA, NA, NA),
+ [47] = PINGROUP(47, qup6, NA, NA, NA, NA, NA, NA, NA, NA),
+ [48] = PINGROUP(48, qup6, NA, NA, NA, NA, NA, NA, NA, NA),
+ [49] = PINGROUP(49, qup12, NA, NA, NA, NA, NA, NA, NA, NA),
+ [50] = PINGROUP(50, qup12, NA, NA, NA, NA, NA, NA, NA, NA),
+ [51] = PINGROUP(51, qup12, qdss_cti, NA, NA, NA, NA, NA, NA, NA),
+ [52] = PINGROUP(52, qup12, phase_flag16, qdss_cti, NA, NA, NA,
NA, NA, NA),
- [53] = PINGROUP(53, NORTH, qup10, phase_flag11, NA, NA, NA, NA, NA, NA,
+ [53] = PINGROUP(53, qup10, phase_flag11, NA, NA, NA, NA, NA, NA,
NA),
- [54] = PINGROUP(54, NORTH, qup10, GP_PDM0, phase_flag12, NA,
+ [54] = PINGROUP(54, qup10, GP_PDM0, phase_flag12, NA,
wlan1_adc1, atest_usb13, ddr_pxi1, NA, NA),
- [55] = PINGROUP(55, NORTH, qup10, phase_flag13, NA, wlan1_adc0,
+ [55] = PINGROUP(55, qup10, phase_flag13, NA, wlan1_adc0,
atest_usb12, ddr_pxi1, NA, NA, NA),
- [56] = PINGROUP(56, NORTH, qup10, phase_flag17, NA, NA, NA, NA, NA, NA,
+ [56] = PINGROUP(56, qup10, phase_flag17, NA, NA, NA, NA, NA, NA,
NA),
- [57] = PINGROUP(57, NORTH, qua_mi2s, gcc_gp1, phase_flag18, NA, NA, NA,
+ [57] = PINGROUP(57, qua_mi2s, gcc_gp1, phase_flag18, NA, NA, NA,
NA, NA, NA),
- [58] = PINGROUP(58, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [59] = PINGROUP(59, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [60] = PINGROUP(60, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [61] = PINGROUP(61, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [62] = PINGROUP(62, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [63] = PINGROUP(63, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [64] = PINGROUP(64, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [65] = PINGROUP(65, NORTH, pri_mi2s, qup8, wsa_clk, NA, NA, NA, NA, NA,
+ [58] = PINGROUP(58, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [59] = PINGROUP(59, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [60] = PINGROUP(60, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [61] = PINGROUP(61, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [62] = PINGROUP(62, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [63] = PINGROUP(63, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [64] = PINGROUP(64, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [65] = PINGROUP(65, pri_mi2s, qup8, wsa_clk, NA, NA, NA, NA, NA,
NA),
- [66] = PINGROUP(66, NORTH, pri_mi2s_ws, qup8, wsa_data, GP_PDM1, NA,
+ [66] = PINGROUP(66, pri_mi2s_ws, qup8, wsa_data, GP_PDM1, NA,
NA, NA, NA, NA),
- [67] = PINGROUP(67, NORTH, pri_mi2s, qup8, NA, atest_usb2, NA, NA, NA,
+ [67] = PINGROUP(67, pri_mi2s, qup8, NA, atest_usb2, NA, NA, NA,
NA, NA),
- [68] = PINGROUP(68, NORTH, pri_mi2s, qup8, NA, atest_usb23, NA, NA, NA,
+ [68] = PINGROUP(68, pri_mi2s, qup8, NA, atest_usb23, NA, NA, NA,
NA, NA),
- [69] = PINGROUP(69, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [70] = PINGROUP(70, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [71] = PINGROUP(71, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [72] = PINGROUP(72, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [73] = PINGROUP(73, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [74] = PINGROUP(74, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [75] = PINGROUP(75, NORTH, ter_mi2s, phase_flag8, qdss_gpio8,
+ [69] = PINGROUP(69, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [70] = PINGROUP(70, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [71] = PINGROUP(71, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [72] = PINGROUP(72, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [73] = PINGROUP(73, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [74] = PINGROUP(74, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [75] = PINGROUP(75, ter_mi2s, phase_flag8, qdss_gpio8,
atest_usb22, QUP_L4, NA, NA, NA, NA),
- [76] = PINGROUP(76, NORTH, ter_mi2s, phase_flag9, qdss_gpio9,
+ [76] = PINGROUP(76, ter_mi2s, phase_flag9, qdss_gpio9,
atest_usb21, QUP_L5, NA, NA, NA, NA),
- [77] = PINGROUP(77, NORTH, ter_mi2s, phase_flag4, qdss_gpio10,
+ [77] = PINGROUP(77, ter_mi2s, phase_flag4, qdss_gpio10,
atest_usb20, QUP_L6, NA, NA, NA, NA),
- [78] = PINGROUP(78, NORTH, ter_mi2s, gcc_gp1, NA, NA, NA, NA, NA, NA,
+ [78] = PINGROUP(78, ter_mi2s, gcc_gp1, NA, NA, NA, NA, NA, NA,
NA),
- [79] = PINGROUP(79, NORTH, sec_mi2s, GP_PDM2, NA, qdss_gpio11, NA, NA,
+ [79] = PINGROUP(79, sec_mi2s, GP_PDM2, NA, qdss_gpio11, NA, NA,
NA, NA, NA),
- [80] = PINGROUP(80, NORTH, sec_mi2s, NA, qdss_gpio12, NA, NA, NA, NA,
+ [80] = PINGROUP(80, sec_mi2s, NA, qdss_gpio12, NA, NA, NA, NA,
NA, NA),
- [81] = PINGROUP(81, NORTH, sec_mi2s, qup15, NA, NA, NA, NA, NA, NA, NA),
- [82] = PINGROUP(82, NORTH, sec_mi2s, qup15, NA, NA, NA, NA, NA, NA, NA),
- [83] = PINGROUP(83, NORTH, sec_mi2s, qup15, NA, NA, NA, NA, NA, NA, NA),
- [84] = PINGROUP(84, NORTH, qup15, NA, NA, NA, NA, NA, NA, NA, NA),
- [85] = PINGROUP(85, SOUTH, qup5, NA, NA, NA, NA, NA, NA, NA, NA),
- [86] = PINGROUP(86, SOUTH, qup5, copy_gp, NA, NA, NA, NA, NA, NA, NA),
- [87] = PINGROUP(87, SOUTH, qup5, NA, NA, NA, NA, NA, NA, NA, NA),
- [88] = PINGROUP(88, SOUTH, qup5, NA, NA, NA, NA, NA, NA, NA, NA),
- [89] = PINGROUP(89, SOUTH, tsif1_clk, qup4, tgu_ch3, phase_flag10, NA,
+ [81] = PINGROUP(81, sec_mi2s, qup15, NA, NA, NA, NA, NA, NA, NA),
+ [82] = PINGROUP(82, sec_mi2s, qup15, NA, NA, NA, NA, NA, NA, NA),
+ [83] = PINGROUP(83, sec_mi2s, qup15, NA, NA, NA, NA, NA, NA, NA),
+ [84] = PINGROUP(84, qup15, NA, NA, NA, NA, NA, NA, NA, NA),
+ [85] = PINGROUP(85, qup5, NA, NA, NA, NA, NA, NA, NA, NA),
+ [86] = PINGROUP(86, qup5, copy_gp, NA, NA, NA, NA, NA, NA, NA),
+ [87] = PINGROUP(87, qup5, NA, NA, NA, NA, NA, NA, NA, NA),
+ [88] = PINGROUP(88, qup5, NA, NA, NA, NA, NA, NA, NA, NA),
+ [89] = PINGROUP(89, tsif1_clk, qup4, tgu_ch3, phase_flag10, NA,
NA, NA, NA, NA),
- [90] = PINGROUP(90, SOUTH, tsif1_en, mdp_vsync0, qup4, mdp_vsync1,
+ [90] = PINGROUP(90, tsif1_en, mdp_vsync0, qup4, mdp_vsync1,
mdp_vsync2, mdp_vsync3, tgu_ch0, phase_flag0, qdss_cti),
- [91] = PINGROUP(91, SOUTH, tsif1_data, sdc4_cmd, qup4, tgu_ch1, NA,
+ [91] = PINGROUP(91, tsif1_data, sdc4_cmd, qup4, tgu_ch1, NA,
qdss_cti, NA, NA, NA),
- [92] = PINGROUP(92, SOUTH, tsif2_error, sdc43, qup4, vfr_1, tgu_ch2,
+ [92] = PINGROUP(92, tsif2_error, sdc43, qup4, vfr_1, tgu_ch2,
NA, NA, NA, NA),
- [93] = PINGROUP(93, SOUTH, tsif2_clk, sdc4_clk, qup7, NA, qdss_gpio13,
+ [93] = PINGROUP(93, tsif2_clk, sdc4_clk, qup7, NA, qdss_gpio13,
NA, NA, NA, NA),
- [94] = PINGROUP(94, SOUTH, tsif2_en, sdc42, qup7, NA, NA, NA, NA, NA,
+ [94] = PINGROUP(94, tsif2_en, sdc42, qup7, NA, NA, NA, NA, NA,
NA),
- [95] = PINGROUP(95, SOUTH, tsif2_data, sdc41, qup7, GP_PDM0, NA, NA,
+ [95] = PINGROUP(95, tsif2_data, sdc41, qup7, GP_PDM0, NA, NA,
NA, NA, NA),
- [96] = PINGROUP(96, SOUTH, tsif2_sync, sdc40, qup7, phase_flag3, NA,
+ [96] = PINGROUP(96, tsif2_sync, sdc40, qup7, phase_flag3, NA,
NA, NA, NA, NA),
- [97] = PINGROUP(97, WEST, NA, NA, mdp_vsync, ldo_en, NA, NA, NA, NA,
+ [97] = PINGROUP(97, NA, NA, mdp_vsync, ldo_en, NA, NA, NA, NA,
NA),
- [98] = PINGROUP(98, WEST, NA, mdp_vsync, ldo_update, NA, NA, NA, NA,
+ [98] = PINGROUP(98, NA, mdp_vsync, ldo_update, NA, NA, NA, NA,
NA, NA),
- [99] = PINGROUP(99, NORTH, phase_flag14, prng_rosc, NA, NA, NA, NA, NA,
+ [99] = PINGROUP(99, phase_flag14, prng_rosc, NA, NA, NA, NA, NA,
NA, NA),
- [100] = PINGROUP(100, WEST, phase_flag15, NA, NA, NA, NA, NA, NA, NA,
+ [100] = PINGROUP(100, phase_flag15, NA, NA, NA, NA, NA, NA, NA,
NA),
- [101] = PINGROUP(101, WEST, NA, phase_flag5, NA, NA, NA, NA, NA, NA,
+ [101] = PINGROUP(101, NA, phase_flag5, NA, NA, NA, NA, NA, NA,
NA),
- [102] = PINGROUP(102, WEST, pci_e1, prng_rosc, NA, NA, NA, NA, NA, NA,
+ [102] = PINGROUP(102, pci_e1, prng_rosc, NA, NA, NA, NA, NA, NA,
NA),
- [103] = PINGROUP(103, WEST, pci_e1, COPY_PHASE, NA, NA, NA, NA, NA, NA,
+ [103] = PINGROUP(103, pci_e1, COPY_PHASE, NA, NA, NA, NA, NA, NA,
NA),
- [104] = PINGROUP(104, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [105] = PINGROUP(105, NORTH, uim2_data, qup13, qup_l4, NA, NA, NA, NA,
+ [104] = PINGROUP(104, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [105] = PINGROUP(105, uim2_data, qup13, qup_l4, NA, NA, NA, NA,
NA, NA),
- [106] = PINGROUP(106, NORTH, uim2_clk, qup13, qup_l5, NA, NA, NA, NA,
+ [106] = PINGROUP(106, uim2_clk, qup13, qup_l5, NA, NA, NA, NA,
NA, NA),
- [107] = PINGROUP(107, NORTH, uim2_reset, qup13, qup_l6, NA, NA, NA, NA,
+ [107] = PINGROUP(107, uim2_reset, qup13, qup_l6, NA, NA, NA, NA,
NA, NA),
- [108] = PINGROUP(108, NORTH, uim2_present, qup13, NA, NA, NA, NA, NA,
+ [108] = PINGROUP(108, uim2_present, qup13, NA, NA, NA, NA, NA,
NA, NA),
- [109] = PINGROUP(109, NORTH, uim1_data, NA, NA, NA, NA, NA, NA, NA, NA),
- [110] = PINGROUP(110, NORTH, uim1_clk, NA, NA, NA, NA, NA, NA, NA, NA),
- [111] = PINGROUP(111, NORTH, uim1_reset, NA, NA, NA, NA, NA, NA, NA,
+ [109] = PINGROUP(109, uim1_data, NA, NA, NA, NA, NA, NA, NA, NA),
+ [110] = PINGROUP(110, uim1_clk, NA, NA, NA, NA, NA, NA, NA, NA),
+ [111] = PINGROUP(111, uim1_reset, NA, NA, NA, NA, NA, NA, NA,
NA),
- [112] = PINGROUP(112, NORTH, uim1_present, NA, NA, NA, NA, NA, NA, NA,
+ [112] = PINGROUP(112, uim1_present, NA, NA, NA, NA, NA, NA, NA,
NA),
- [113] = PINGROUP(113, NORTH, uim_batt, edp_hot, NA, NA, NA, NA, NA, NA,
+ [113] = PINGROUP(113, uim_batt, edp_hot, NA, NA, NA, NA, NA, NA,
NA),
- [114] = PINGROUP(114, WEST, NA, NAV_PPS, NAV_PPS, GPS_TX, NA, NA, NA,
+ [114] = PINGROUP(114, NA, NAV_PPS, NAV_PPS, GPS_TX, NA, NA, NA,
NA, NA),
- [115] = PINGROUP(115, WEST, NA, NAV_PPS, NAV_PPS, GPS_TX, NA, NA, NA,
+ [115] = PINGROUP(115, NA, NAV_PPS, NAV_PPS, GPS_TX, NA, NA, NA,
NA, NA),
- [116] = PINGROUP(116, SOUTH, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [117] = PINGROUP(117, NORTH, NA, qdss_gpio0, atest_char, NA, NA, NA,
+ [116] = PINGROUP(116, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [117] = PINGROUP(117, NA, qdss_gpio0, atest_char, NA, NA, NA,
NA, NA, NA),
- [118] = PINGROUP(118, NORTH, adsp_ext, NA, qdss_gpio1, atest_char3, NA,
+ [118] = PINGROUP(118, adsp_ext, NA, qdss_gpio1, atest_char3, NA,
NA, NA, NA, NA),
- [119] = PINGROUP(119, NORTH, NA, qdss_gpio2, atest_char2, NA, NA, NA,
+ [119] = PINGROUP(119, NA, qdss_gpio2, atest_char2, NA, NA, NA,
NA, NA, NA),
- [120] = PINGROUP(120, NORTH, NA, qdss_gpio3, atest_char1, NA, NA, NA,
+ [120] = PINGROUP(120, NA, qdss_gpio3, atest_char1, NA, NA, NA,
NA, NA, NA),
- [121] = PINGROUP(121, NORTH, NA, qdss_gpio4, atest_char0, NA, NA, NA,
+ [121] = PINGROUP(121, NA, qdss_gpio4, atest_char0, NA, NA, NA,
NA, NA, NA),
- [122] = PINGROUP(122, NORTH, NA, qdss_gpio5, NA, NA, NA, NA, NA, NA,
+ [122] = PINGROUP(122, NA, qdss_gpio5, NA, NA, NA, NA, NA, NA,
NA),
- [123] = PINGROUP(123, NORTH, qup_l4, NA, qdss_gpio, NA, NA, NA, NA, NA,
+ [123] = PINGROUP(123, qup_l4, NA, qdss_gpio, NA, NA, NA, NA, NA,
NA),
- [124] = PINGROUP(124, NORTH, qup_l5, NA, qdss_gpio, NA, NA, NA, NA, NA,
+ [124] = PINGROUP(124, qup_l5, NA, qdss_gpio, NA, NA, NA, NA, NA,
NA),
- [125] = PINGROUP(125, NORTH, qup_l6, NA, NA, NA, NA, NA, NA, NA, NA),
- [126] = PINGROUP(126, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [127] = PINGROUP(127, WEST, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [128] = PINGROUP(128, WEST, NAV_PPS, NAV_PPS, GPS_TX, NA, NA, NA, NA,
+ [125] = PINGROUP(125, qup_l6, NA, NA, NA, NA, NA, NA, NA, NA),
+ [126] = PINGROUP(126, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [127] = PINGROUP(127, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [128] = PINGROUP(128, NAV_PPS, NAV_PPS, GPS_TX, NA, NA, NA, NA,
NA, NA),
- [129] = PINGROUP(129, WEST, NAV_PPS, NAV_PPS, GPS_TX, NA, NA, NA, NA,
+ [129] = PINGROUP(129, NAV_PPS, NAV_PPS, GPS_TX, NA, NA, NA, NA,
NA, NA),
- [130] = PINGROUP(130, WEST, qlink_request, NA, NA, NA, NA, NA, NA, NA,
+ [130] = PINGROUP(130, qlink_request, NA, NA, NA, NA, NA, NA, NA,
NA),
- [131] = PINGROUP(131, WEST, qlink_enable, NA, NA, NA, NA, NA, NA, NA,
+ [131] = PINGROUP(131, qlink_enable, NA, NA, NA, NA, NA, NA, NA,
NA),
- [132] = PINGROUP(132, WEST, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [133] = PINGROUP(133, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [134] = PINGROUP(134, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [135] = PINGROUP(135, WEST, NA, pa_indicator, NA, NA, NA, NA, NA, NA,
+ [132] = PINGROUP(132, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [133] = PINGROUP(133, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [134] = PINGROUP(134, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [135] = PINGROUP(135, NA, pa_indicator, NA, NA, NA, NA, NA, NA,
NA),
- [136] = PINGROUP(136, WEST, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [137] = PINGROUP(137, WEST, NA, NA, phase_flag26, NA, NA, NA, NA, NA,
+ [136] = PINGROUP(136, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [137] = PINGROUP(137, NA, NA, phase_flag26, NA, NA, NA, NA, NA,
NA),
- [138] = PINGROUP(138, WEST, NA, NA, phase_flag27, NA, NA, NA, NA, NA,
+ [138] = PINGROUP(138, NA, NA, phase_flag27, NA, NA, NA, NA, NA,
NA),
- [139] = PINGROUP(139, WEST, NA, phase_flag28, NA, NA, NA, NA, NA, NA,
+ [139] = PINGROUP(139, NA, phase_flag28, NA, NA, NA, NA, NA, NA,
NA),
- [140] = PINGROUP(140, WEST, NA, NA, phase_flag6, NA, NA, NA, NA, NA,
+ [140] = PINGROUP(140, NA, NA, phase_flag6, NA, NA, NA, NA, NA,
NA),
- [141] = PINGROUP(141, WEST, NA, phase_flag29, NA, NA, NA, NA, NA, NA,
+ [141] = PINGROUP(141, NA, phase_flag29, NA, NA, NA, NA, NA, NA,
NA),
- [142] = PINGROUP(142, WEST, NA, phase_flag30, NA, NA, NA, NA, NA, NA,
+ [142] = PINGROUP(142, NA, phase_flag30, NA, NA, NA, NA, NA, NA,
NA),
- [143] = PINGROUP(143, WEST, NA, NAV_PPS, NAV_PPS, GPS_TX, phase_flag31,
+ [143] = PINGROUP(143, NA, NAV_PPS, NAV_PPS, GPS_TX, phase_flag31,
NA, NA, NA, NA),
- [144] = PINGROUP(144, SOUTH, mss_lte, NA, NA, NA, NA, NA, NA, NA, NA),
- [145] = PINGROUP(145, SOUTH, mss_lte, GPS_TX, NA, NA, NA, NA, NA, NA,
+ [144] = PINGROUP(144, mss_lte, NA, NA, NA, NA, NA, NA, NA, NA),
+ [145] = PINGROUP(145, mss_lte, GPS_TX, NA, NA, NA, NA, NA, NA,
NA),
- [146] = PINGROUP(146, WEST, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [147] = PINGROUP(147, WEST, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [148] = PINGROUP(148, WEST, NA, NA, NA, NA, NA, NA, NA, NA, NA),
- [149] = PINGROUP(149, WEST, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [146] = PINGROUP(146, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [147] = PINGROUP(147, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [148] = PINGROUP(148, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [149] = PINGROUP(149, NA, NA, NA, NA, NA, NA, NA, NA, NA),
[150] = SDC_QDSD_PINGROUP(sdc1_rclk, 0x599000, 15, 0),
[151] = SDC_QDSD_PINGROUP(sdc1_clk, 0x599000, 13, 6),
[152] = SDC_QDSD_PINGROUP(sdc1_cmd, 0x599000, 11, 3),
@@ -1593,6 +1593,10 @@
.groups = sdm670_groups,
.ngroups = ARRAY_SIZE(sdm670_groups),
.ngpios = 150,
+ .tile_offsets = sdm670_tile_offsets,
+ .n_tile_offsets = ARRAY_SIZE(sdm670_tile_offsets),
+ .pin_base = sdm670_pin_base,
+ .reg_size = REG_SIZE,
};
static int sdm670_pinctrl_probe(struct platform_device *pdev)
diff --git a/drivers/pinctrl/qcom/pinctrl-sdm845.c b/drivers/pinctrl/qcom/pinctrl-sdm845.c
index 7d125eb..8faabb0 100644
--- a/drivers/pinctrl/qcom/pinctrl-sdm845.c
+++ b/drivers/pinctrl/qcom/pinctrl-sdm845.c
@@ -25,10 +25,8 @@
.ngroups = ARRAY_SIZE(fname##_groups), \
}
-#define NORTH 0x00500000
-#define SOUTH 0x00900000
#define REG_SIZE 0x1000
-#define PINGROUP(id, base, f1, f2, f3, f4, f5, f6, f7, f8, f9) \
+#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9) \
{ \
.name = "gpio" #id, \
.pins = gpio##id##_pins, \
@@ -46,11 +44,11 @@
msm_mux_##f9 \
}, \
.nfuncs = 10, \
- .ctl_reg = base + REG_SIZE * id, \
- .io_reg = base + 0x4 + REG_SIZE * id, \
- .intr_cfg_reg = base + 0x8 + REG_SIZE * id, \
- .intr_status_reg = base + 0xc + REG_SIZE * id, \
- .intr_target_reg = base + 0x8 + REG_SIZE * id, \
+ .ctl_reg = REG_SIZE * id, \
+ .io_reg = 0x4 + REG_SIZE * id, \
+ .intr_cfg_reg = 0x8 + REG_SIZE * id, \
+ .intr_status_reg = 0xc + REG_SIZE * id, \
+ .intr_target_reg = 0x8 + REG_SIZE * id, \
.mux_bit = 2, \
.pull_bit = 0, \
.drv_bit = 6, \
@@ -116,6 +114,10 @@
.intr_detection_bit = -1, \
.intr_detection_width = -1, \
}
+
+static const u32 sdm845_tile_offsets[] = {0x500000, 0x900000, 0x100000};
+static u32 sdm845_pin_base[150];
+
static const struct pinctrl_pin_desc sdm845_pins[] = {
PINCTRL_PIN(0, "GPIO_0"),
PINCTRL_PIN(1, "GPIO_1"),
@@ -432,306 +434,99 @@
static const unsigned int ufs_reset_pins[] = { 153 };
enum sdm845_functions {
- msm_mux_gpio,
- msm_mux_qup0,
- msm_mux_reserved0,
- msm_mux_reserved1,
- msm_mux_reserved2,
- msm_mux_reserved3,
- msm_mux_qup9,
- msm_mux_qdss_cti,
- msm_mux_reserved4,
- msm_mux_reserved5,
- msm_mux_ddr_pxi0,
- msm_mux_reserved6,
- msm_mux_ddr_bist,
- msm_mux_atest_tsens2,
- msm_mux_vsense_trigger,
- msm_mux_atest_usb1,
- msm_mux_reserved7,
- msm_mux_qup_l4,
- msm_mux_wlan1_adc1,
- msm_mux_atest_usb13,
- msm_mux_ddr_pxi1,
- msm_mux_reserved8,
- msm_mux_qup_l5,
- msm_mux_wlan1_adc0,
- msm_mux_atest_usb12,
- msm_mux_reserved9,
- msm_mux_mdp_vsync,
- msm_mux_qup_l6,
- msm_mux_wlan2_adc1,
- msm_mux_atest_usb11,
- msm_mux_ddr_pxi2,
- msm_mux_reserved10,
- msm_mux_edp_lcd,
- msm_mux_dbg_out,
- msm_mux_wlan2_adc0,
- msm_mux_atest_usb10,
- msm_mux_reserved11,
- msm_mux_m_voc,
- msm_mux_tsif1_sync,
msm_mux_ddr_pxi3,
- msm_mux_reserved12,
msm_mux_cam_mclk,
msm_mux_pll_bypassnl,
msm_mux_qdss_gpio0,
- msm_mux_reserved13,
msm_mux_pll_reset,
msm_mux_qdss_gpio1,
- msm_mux_reserved14,
msm_mux_qdss_gpio2,
- msm_mux_reserved15,
msm_mux_qdss_gpio3,
- msm_mux_reserved16,
msm_mux_cci_i2c,
msm_mux_qup1,
msm_mux_qdss_gpio4,
- msm_mux_reserved17,
msm_mux_qdss_gpio5,
- msm_mux_reserved18,
msm_mux_qdss_gpio6,
- msm_mux_reserved19,
msm_mux_qdss_gpio7,
- msm_mux_reserved20,
msm_mux_cci_timer0,
msm_mux_gcc_gp2,
msm_mux_qdss_gpio8,
- msm_mux_reserved21,
msm_mux_cci_timer1,
msm_mux_gcc_gp3,
msm_mux_qdss_gpio,
- msm_mux_reserved22,
msm_mux_cci_timer2,
msm_mux_qdss_gpio9,
- msm_mux_reserved23,
msm_mux_cci_timer3,
msm_mux_cci_async,
msm_mux_qdss_gpio10,
- msm_mux_reserved24,
msm_mux_cci_timer4,
msm_mux_qdss_gpio11,
- msm_mux_reserved25,
msm_mux_qdss_gpio12,
- msm_mux_reserved26,
msm_mux_qup2,
msm_mux_qdss_gpio13,
- msm_mux_reserved27,
msm_mux_qdss_gpio14,
- msm_mux_reserved28,
msm_mux_phase_flag1,
msm_mux_qdss_gpio15,
- msm_mux_reserved29,
msm_mux_phase_flag2,
- msm_mux_reserved30,
msm_mux_qup11,
msm_mux_qup14,
- msm_mux_reserved96,
- msm_mux_ldo_en,
- msm_mux_reserved97,
- msm_mux_ldo_update,
- msm_mux_reserved98,
- msm_mux_phase_flag14,
- msm_mux_reserved99,
- msm_mux_phase_flag15,
- msm_mux_reserved100,
- msm_mux_reserved101,
- msm_mux_pci_e1,
- msm_mux_prng_rosc,
- msm_mux_reserved102,
- msm_mux_phase_flag5,
- msm_mux_reserved103,
- msm_mux_reserved104,
- msm_mux_uim2_data,
- msm_mux_qup13,
- msm_mux_reserved105,
- msm_mux_uim2_clk,
- msm_mux_reserved106,
- msm_mux_uim2_reset,
- msm_mux_reserved107,
- msm_mux_uim2_present,
- msm_mux_reserved108,
- msm_mux_uim1_data,
- msm_mux_reserved109,
- msm_mux_uim1_clk,
- msm_mux_reserved110,
- msm_mux_uim1_reset,
- msm_mux_reserved111,
- msm_mux_uim1_present,
- msm_mux_reserved112,
- msm_mux_uim_batt,
- msm_mux_edp_hot,
- msm_mux_reserved113,
- msm_mux_nav_pps,
- msm_mux_reserved114,
- msm_mux_reserved115,
- msm_mux_reserved116,
- msm_mux_atest_char,
- msm_mux_reserved117,
- msm_mux_adsp_ext,
- msm_mux_atest_char3,
- msm_mux_reserved118,
- msm_mux_atest_char2,
- msm_mux_reserved119,
- msm_mux_atest_char1,
- msm_mux_reserved120,
- msm_mux_atest_char0,
- msm_mux_reserved121,
- msm_mux_reserved122,
- msm_mux_reserved123,
- msm_mux_reserved124,
- msm_mux_reserved125,
- msm_mux_reserved126,
- msm_mux_reserved127,
- msm_mux_reserved128,
- msm_mux_reserved129,
- msm_mux_qlink_request,
- msm_mux_reserved130,
- msm_mux_qlink_enable,
- msm_mux_reserved131,
- msm_mux_reserved132,
- msm_mux_reserved133,
- msm_mux_reserved134,
- msm_mux_pa_indicator,
- msm_mux_reserved135,
- msm_mux_reserved136,
- msm_mux_phase_flag26,
- msm_mux_reserved137,
- msm_mux_phase_flag27,
- msm_mux_reserved138,
- msm_mux_phase_flag28,
- msm_mux_reserved139,
- msm_mux_phase_flag6,
- msm_mux_reserved140,
- msm_mux_phase_flag29,
- msm_mux_reserved141,
- msm_mux_phase_flag30,
- msm_mux_reserved142,
- msm_mux_phase_flag31,
- msm_mux_reserved143,
- msm_mux_mss_lte,
- msm_mux_reserved144,
- msm_mux_reserved145,
- msm_mux_reserved146,
- msm_mux_reserved147,
- msm_mux_reserved148,
- msm_mux_reserved149,
- msm_mux_reserved31,
- msm_mux_reserved32,
- msm_mux_reserved33,
- msm_mux_reserved34,
msm_mux_pci_e0,
msm_mux_jitter_bist,
- msm_mux_reserved35,
msm_mux_pll_bist,
msm_mux_atest_tsens,
- msm_mux_reserved36,
msm_mux_agera_pll,
- msm_mux_reserved37,
msm_mux_usb_phy,
- msm_mux_reserved38,
msm_mux_lpass_slimbus,
- msm_mux_reserved39,
msm_mux_sd_write,
msm_mux_tsif1_error,
- msm_mux_reserved40,
msm_mux_qup3,
- msm_mux_reserved41,
- msm_mux_reserved42,
- msm_mux_reserved43,
- msm_mux_reserved44,
msm_mux_qup6,
- msm_mux_reserved45,
- msm_mux_reserved46,
- msm_mux_reserved47,
- msm_mux_reserved48,
msm_mux_qup12,
- msm_mux_reserved49,
- msm_mux_reserved50,
- msm_mux_reserved51,
msm_mux_phase_flag16,
- msm_mux_reserved52,
msm_mux_qup10,
msm_mux_phase_flag11,
- msm_mux_reserved53,
msm_mux_phase_flag12,
- msm_mux_reserved54,
msm_mux_phase_flag13,
- msm_mux_reserved55,
msm_mux_phase_flag17,
- msm_mux_reserved56,
msm_mux_qua_mi2s,
msm_mux_gcc_gp1,
msm_mux_phase_flag18,
- msm_mux_reserved57,
msm_mux_phase_flag19,
- msm_mux_reserved58,
msm_mux_phase_flag20,
- msm_mux_reserved59,
msm_mux_cri_trng0,
msm_mux_phase_flag21,
- msm_mux_reserved60,
msm_mux_cri_trng1,
msm_mux_phase_flag22,
- msm_mux_reserved61,
msm_mux_cri_trng,
msm_mux_phase_flag23,
- msm_mux_reserved62,
msm_mux_phase_flag24,
- msm_mux_reserved63,
msm_mux_pri_mi2s,
msm_mux_sp_cmu,
msm_mux_phase_flag25,
- msm_mux_reserved64,
msm_mux_qup8,
- msm_mux_reserved65,
msm_mux_pri_mi2s_ws,
- msm_mux_reserved66,
- msm_mux_reserved67,
- msm_mux_reserved68,
msm_mux_spkr_i2s,
msm_mux_audio_ref,
- msm_mux_reserved69,
- msm_mux_reserved70,
msm_mux_tsense_pwm1,
msm_mux_tsense_pwm2,
- msm_mux_reserved71,
- msm_mux_reserved72,
msm_mux_btfm_slimbus,
msm_mux_atest_usb2,
- msm_mux_reserved73,
msm_mux_ter_mi2s,
msm_mux_phase_flag7,
msm_mux_atest_usb23,
- msm_mux_reserved74,
msm_mux_phase_flag8,
msm_mux_atest_usb22,
- msm_mux_reserved75,
msm_mux_phase_flag9,
msm_mux_atest_usb21,
- msm_mux_reserved76,
msm_mux_phase_flag4,
msm_mux_atest_usb20,
- msm_mux_reserved77,
- msm_mux_reserved78,
msm_mux_sec_mi2s,
- msm_mux_reserved79,
- msm_mux_reserved80,
msm_mux_qup15,
- msm_mux_reserved81,
- msm_mux_reserved82,
- msm_mux_reserved83,
- msm_mux_reserved84,
msm_mux_qup5,
- msm_mux_reserved85,
- msm_mux_reserved86,
- msm_mux_reserved87,
- msm_mux_reserved88,
msm_mux_tsif1_clk,
msm_mux_qup4,
msm_mux_tgu_ch3,
msm_mux_phase_flag10,
- msm_mux_reserved89,
msm_mux_tsif1_en,
msm_mux_mdp_vsync0,
msm_mux_mdp_vsync1,
@@ -739,32 +534,552 @@
msm_mux_mdp_vsync3,
msm_mux_tgu_ch0,
msm_mux_phase_flag0,
- msm_mux_reserved90,
msm_mux_tsif1_data,
msm_mux_sdc4_cmd,
msm_mux_tgu_ch1,
- msm_mux_reserved91,
msm_mux_tsif2_error,
msm_mux_sdc43,
msm_mux_vfr_1,
msm_mux_tgu_ch2,
- msm_mux_reserved92,
msm_mux_tsif2_clk,
msm_mux_sdc4_clk,
msm_mux_qup7,
- msm_mux_reserved93,
msm_mux_tsif2_en,
msm_mux_sdc42,
- msm_mux_reserved94,
msm_mux_tsif2_data,
msm_mux_sdc41,
- msm_mux_reserved95,
msm_mux_tsif2_sync,
msm_mux_sdc40,
msm_mux_phase_flag3,
+ msm_mux_ldo_en,
+ msm_mux_ldo_update,
+ msm_mux_phase_flag14,
+ msm_mux_phase_flag15,
+ msm_mux_pci_e1,
+ msm_mux_prng_rosc,
+ msm_mux_phase_flag5,
+ msm_mux_uim2_data,
+ msm_mux_qup13,
+ msm_mux_uim2_clk,
+ msm_mux_uim2_reset,
+ msm_mux_uim2_present,
+ msm_mux_uim1_data,
+ msm_mux_uim1_clk,
+ msm_mux_uim1_reset,
+ msm_mux_uim1_present,
+ msm_mux_uim_batt,
+ msm_mux_edp_hot,
+ msm_mux_nav_pps,
+ msm_mux_atest_char,
+ msm_mux_adsp_ext,
+ msm_mux_atest_char3,
+ msm_mux_atest_char2,
+ msm_mux_atest_char1,
+ msm_mux_atest_char0,
+ msm_mux_qlink_request,
+ msm_mux_qlink_enable,
+ msm_mux_pa_indicator,
+ msm_mux_phase_flag26,
+ msm_mux_phase_flag27,
+ msm_mux_phase_flag28,
+ msm_mux_phase_flag6,
+ msm_mux_phase_flag29,
+ msm_mux_phase_flag30,
+ msm_mux_phase_flag31,
+ msm_mux_mss_lte,
+ msm_mux_qup0,
+ msm_mux_gpio,
+ msm_mux_qup9,
+ msm_mux_qdss_cti,
+ msm_mux_ddr_pxi0,
+ msm_mux_ddr_bist,
+ msm_mux_atest_tsens2,
+ msm_mux_vsense_trigger,
+ msm_mux_atest_usb1,
+ msm_mux_qup_l4,
+ msm_mux_wlan1_adc1,
+ msm_mux_atest_usb13,
+ msm_mux_ddr_pxi1,
+ msm_mux_qup_l5,
+ msm_mux_wlan1_adc0,
+ msm_mux_atest_usb12,
+ msm_mux_mdp_vsync,
+ msm_mux_qup_l6,
+ msm_mux_wlan2_adc1,
+ msm_mux_atest_usb11,
+ msm_mux_ddr_pxi2,
+ msm_mux_edp_lcd,
+ msm_mux_dbg_out,
+ msm_mux_wlan2_adc0,
+ msm_mux_atest_usb10,
+ msm_mux_m_voc,
+ msm_mux_tsif1_sync,
msm_mux_NA,
};
+static const char * const ddr_pxi3_groups[] = {
+ "gpio12", "gpio13",
+};
+static const char * const cam_mclk_groups[] = {
+ "gpio13", "gpio14", "gpio15", "gpio16",
+};
+static const char * const pll_bypassnl_groups[] = {
+ "gpio13",
+};
+static const char * const qdss_gpio0_groups[] = {
+ "gpio13", "gpio117",
+};
+static const char * const pll_reset_groups[] = {
+ "gpio14",
+};
+static const char * const qdss_gpio1_groups[] = {
+ "gpio14", "gpio118",
+};
+static const char * const qdss_gpio2_groups[] = {
+ "gpio15", "gpio119",
+};
+static const char * const qdss_gpio3_groups[] = {
+ "gpio16", "gpio120",
+};
+static const char * const cci_i2c_groups[] = {
+ "gpio17", "gpio18", "gpio19", "gpio20",
+};
+static const char * const qup1_groups[] = {
+ "gpio17", "gpio18", "gpio19", "gpio20",
+};
+static const char * const qdss_gpio4_groups[] = {
+ "gpio17", "gpio121",
+};
+static const char * const qdss_gpio5_groups[] = {
+ "gpio18", "gpio122",
+};
+static const char * const qdss_gpio6_groups[] = {
+ "gpio19", "gpio41",
+};
+static const char * const qdss_gpio7_groups[] = {
+ "gpio20", "gpio42",
+};
+static const char * const cci_timer0_groups[] = {
+ "gpio21",
+};
+static const char * const gcc_gp2_groups[] = {
+ "gpio21", "gpio58",
+};
+static const char * const qdss_gpio8_groups[] = {
+ "gpio21", "gpio75",
+};
+static const char * const cci_timer1_groups[] = {
+ "gpio22",
+};
+static const char * const gcc_gp3_groups[] = {
+ "gpio22", "gpio59",
+};
+static const char * const qdss_gpio_groups[] = {
+ "gpio22", "gpio30", "gpio123", "gpio124",
+};
+static const char * const cci_timer2_groups[] = {
+ "gpio23",
+};
+static const char * const qdss_gpio9_groups[] = {
+ "gpio23", "gpio76",
+};
+static const char * const cci_timer3_groups[] = {
+ "gpio24",
+};
+static const char * const cci_async_groups[] = {
+ "gpio24", "gpio25", "gpio26",
+};
+static const char * const qdss_gpio10_groups[] = {
+ "gpio24", "gpio77",
+};
+static const char * const cci_timer4_groups[] = {
+ "gpio25",
+};
+static const char * const qdss_gpio11_groups[] = {
+ "gpio25", "gpio79",
+};
+static const char * const qdss_gpio12_groups[] = {
+ "gpio26", "gpio80",
+};
+static const char * const qup2_groups[] = {
+ "gpio27", "gpio28", "gpio29", "gpio30",
+};
+static const char * const qdss_gpio13_groups[] = {
+ "gpio27", "gpio93",
+};
+static const char * const qdss_gpio14_groups[] = {
+ "gpio28", "gpio43",
+};
+static const char * const phase_flag1_groups[] = {
+ "gpio29",
+};
+static const char * const qdss_gpio15_groups[] = {
+ "gpio29", "gpio44",
+};
+static const char * const phase_flag2_groups[] = {
+ "gpio30",
+};
+static const char * const qup11_groups[] = {
+ "gpio31", "gpio32", "gpio33", "gpio34",
+};
+static const char * const qup14_groups[] = {
+ "gpio31", "gpio32", "gpio33", "gpio34",
+};
+static const char * const pci_e0_groups[] = {
+ "gpio35", "gpio36",
+};
+static const char * const jitter_bist_groups[] = {
+ "gpio35",
+};
+static const char * const pll_bist_groups[] = {
+ "gpio36",
+};
+static const char * const atest_tsens_groups[] = {
+ "gpio36",
+};
+static const char * const agera_pll_groups[] = {
+ "gpio37",
+};
+static const char * const usb_phy_groups[] = {
+ "gpio38",
+};
+static const char * const lpass_slimbus_groups[] = {
+ "gpio39", "gpio70", "gpio71", "gpio72",
+};
+static const char * const sd_write_groups[] = {
+ "gpio40",
+};
+static const char * const tsif1_error_groups[] = {
+ "gpio40",
+};
+static const char * const qup3_groups[] = {
+ "gpio41", "gpio42", "gpio43", "gpio44",
+};
+static const char * const qup6_groups[] = {
+ "gpio45", "gpio46", "gpio47", "gpio48",
+};
+static const char * const qup12_groups[] = {
+ "gpio49", "gpio50", "gpio51", "gpio52",
+};
+static const char * const phase_flag16_groups[] = {
+ "gpio52",
+};
+static const char * const qup10_groups[] = {
+ "gpio53", "gpio54", "gpio55", "gpio56",
+};
+static const char * const phase_flag11_groups[] = {
+ "gpio53",
+};
+static const char * const phase_flag12_groups[] = {
+ "gpio54",
+};
+static const char * const phase_flag13_groups[] = {
+ "gpio55",
+};
+static const char * const phase_flag17_groups[] = {
+ "gpio56",
+};
+static const char * const qua_mi2s_groups[] = {
+ "gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63",
+};
+static const char * const gcc_gp1_groups[] = {
+ "gpio57", "gpio78",
+};
+static const char * const phase_flag18_groups[] = {
+ "gpio57",
+};
+static const char * const phase_flag19_groups[] = {
+ "gpio58",
+};
+static const char * const phase_flag20_groups[] = {
+ "gpio59",
+};
+static const char * const cri_trng0_groups[] = {
+ "gpio60",
+};
+static const char * const phase_flag21_groups[] = {
+ "gpio60",
+};
+static const char * const cri_trng1_groups[] = {
+ "gpio61",
+};
+static const char * const phase_flag22_groups[] = {
+ "gpio61",
+};
+static const char * const cri_trng_groups[] = {
+ "gpio62",
+};
+static const char * const phase_flag23_groups[] = {
+ "gpio62",
+};
+static const char * const phase_flag24_groups[] = {
+ "gpio63",
+};
+static const char * const pri_mi2s_groups[] = {
+ "gpio64", "gpio65", "gpio67", "gpio68",
+};
+static const char * const sp_cmu_groups[] = {
+ "gpio64",
+};
+static const char * const phase_flag25_groups[] = {
+ "gpio64",
+};
+static const char * const qup8_groups[] = {
+ "gpio65", "gpio66", "gpio67", "gpio68",
+};
+static const char * const pri_mi2s_ws_groups[] = {
+ "gpio66",
+};
+static const char * const spkr_i2s_groups[] = {
+ "gpio69", "gpio70", "gpio71", "gpio72",
+};
+static const char * const audio_ref_groups[] = {
+ "gpio69",
+};
+static const char * const tsense_pwm1_groups[] = {
+ "gpio71",
+};
+static const char * const tsense_pwm2_groups[] = {
+ "gpio71",
+};
+static const char * const btfm_slimbus_groups[] = {
+ "gpio73", "gpio74",
+};
+static const char * const atest_usb2_groups[] = {
+ "gpio73",
+};
+static const char * const ter_mi2s_groups[] = {
+ "gpio74", "gpio75", "gpio76", "gpio77", "gpio78",
+};
+static const char * const phase_flag7_groups[] = {
+ "gpio74",
+};
+static const char * const atest_usb23_groups[] = {
+ "gpio74",
+};
+static const char * const phase_flag8_groups[] = {
+ "gpio75",
+};
+static const char * const atest_usb22_groups[] = {
+ "gpio75",
+};
+static const char * const phase_flag9_groups[] = {
+ "gpio76",
+};
+static const char * const atest_usb21_groups[] = {
+ "gpio76",
+};
+static const char * const phase_flag4_groups[] = {
+ "gpio77",
+};
+static const char * const atest_usb20_groups[] = {
+ "gpio77",
+};
+static const char * const sec_mi2s_groups[] = {
+ "gpio79", "gpio80", "gpio81", "gpio82", "gpio83",
+};
+static const char * const qup15_groups[] = {
+ "gpio81", "gpio82", "gpio83", "gpio84",
+};
+static const char * const qup5_groups[] = {
+ "gpio85", "gpio86", "gpio87", "gpio88",
+};
+static const char * const tsif1_clk_groups[] = {
+ "gpio89",
+};
+static const char * const qup4_groups[] = {
+ "gpio89", "gpio90", "gpio91", "gpio92",
+};
+static const char * const tgu_ch3_groups[] = {
+ "gpio89",
+};
+static const char * const phase_flag10_groups[] = {
+ "gpio89",
+};
+static const char * const tsif1_en_groups[] = {
+ "gpio90",
+};
+static const char * const mdp_vsync0_groups[] = {
+ "gpio90",
+};
+static const char * const mdp_vsync1_groups[] = {
+ "gpio90",
+};
+static const char * const mdp_vsync2_groups[] = {
+ "gpio90",
+};
+static const char * const mdp_vsync3_groups[] = {
+ "gpio90",
+};
+static const char * const tgu_ch0_groups[] = {
+ "gpio90",
+};
+static const char * const phase_flag0_groups[] = {
+ "gpio90",
+};
+static const char * const tsif1_data_groups[] = {
+ "gpio91",
+};
+static const char * const sdc4_cmd_groups[] = {
+ "gpio91",
+};
+static const char * const tgu_ch1_groups[] = {
+ "gpio91",
+};
+static const char * const tsif2_error_groups[] = {
+ "gpio92",
+};
+static const char * const sdc43_groups[] = {
+ "gpio92",
+};
+static const char * const vfr_1_groups[] = {
+ "gpio92",
+};
+static const char * const tgu_ch2_groups[] = {
+ "gpio92",
+};
+static const char * const tsif2_clk_groups[] = {
+ "gpio93",
+};
+static const char * const sdc4_clk_groups[] = {
+ "gpio93",
+};
+static const char * const qup7_groups[] = {
+ "gpio93", "gpio94", "gpio95", "gpio96",
+};
+static const char * const tsif2_en_groups[] = {
+ "gpio94",
+};
+static const char * const sdc42_groups[] = {
+ "gpio94",
+};
+static const char * const tsif2_data_groups[] = {
+ "gpio95",
+};
+static const char * const sdc41_groups[] = {
+ "gpio95",
+};
+static const char * const tsif2_sync_groups[] = {
+ "gpio96",
+};
+static const char * const sdc40_groups[] = {
+ "gpio96",
+};
+static const char * const phase_flag3_groups[] = {
+ "gpio96",
+};
+static const char * const ldo_en_groups[] = {
+ "gpio97",
+};
+static const char * const ldo_update_groups[] = {
+ "gpio98",
+};
+static const char * const phase_flag14_groups[] = {
+ "gpio99",
+};
+static const char * const phase_flag15_groups[] = {
+ "gpio100",
+};
+static const char * const pci_e1_groups[] = {
+ "gpio102", "gpio103",
+};
+static const char * const prng_rosc_groups[] = {
+ "gpio102",
+};
+static const char * const phase_flag5_groups[] = {
+ "gpio103",
+};
+static const char * const uim2_data_groups[] = {
+ "gpio105",
+};
+static const char * const qup13_groups[] = {
+ "gpio105", "gpio106", "gpio107", "gpio108",
+};
+static const char * const uim2_clk_groups[] = {
+ "gpio106",
+};
+static const char * const uim2_reset_groups[] = {
+ "gpio107",
+};
+static const char * const uim2_present_groups[] = {
+ "gpio108",
+};
+static const char * const uim1_data_groups[] = {
+ "gpio109",
+};
+static const char * const uim1_clk_groups[] = {
+ "gpio110",
+};
+static const char * const uim1_reset_groups[] = {
+ "gpio111",
+};
+static const char * const uim1_present_groups[] = {
+ "gpio112",
+};
+static const char * const uim_batt_groups[] = {
+ "gpio113",
+};
+static const char * const edp_hot_groups[] = {
+ "gpio113",
+};
+static const char * const nav_pps_groups[] = {
+ "gpio114", "gpio114", "gpio115", "gpio115", "gpio128", "gpio128",
+ "gpio129", "gpio129", "gpio143", "gpio143",
+};
+static const char * const atest_char_groups[] = {
+ "gpio117",
+};
+static const char * const adsp_ext_groups[] = {
+ "gpio118",
+};
+static const char * const atest_char3_groups[] = {
+ "gpio118",
+};
+static const char * const atest_char2_groups[] = {
+ "gpio119",
+};
+static const char * const atest_char1_groups[] = {
+ "gpio120",
+};
+static const char * const atest_char0_groups[] = {
+ "gpio121",
+};
+static const char * const qlink_request_groups[] = {
+ "gpio130",
+};
+static const char * const qlink_enable_groups[] = {
+ "gpio131",
+};
+static const char * const pa_indicator_groups[] = {
+ "gpio135",
+};
+static const char * const phase_flag26_groups[] = {
+ "gpio137",
+};
+static const char * const phase_flag27_groups[] = {
+ "gpio138",
+};
+static const char * const phase_flag28_groups[] = {
+ "gpio139",
+};
+static const char * const phase_flag6_groups[] = {
+ "gpio140",
+};
+static const char * const phase_flag29_groups[] = {
+ "gpio141",
+};
+static const char * const phase_flag30_groups[] = {
+ "gpio142",
+};
+static const char * const phase_flag31_groups[] = {
+ "gpio143",
+};
+static const char * const mss_lte_groups[] = {
+ "gpio144", "gpio145",
+};
+static const char * const qup0_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3",
+};
static const char * const gpio_groups[] = {
"gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7",
"gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14",
@@ -790,21 +1105,6 @@
"gpio141", "gpio142", "gpio143", "gpio144", "gpio145", "gpio146",
"gpio147", "gpio148", "gpio149",
};
-static const char * const qup0_groups[] = {
- "gpio0", "gpio1", "gpio2", "gpio3",
-};
-static const char * const reserved0_groups[] = {
- "gpio0",
-};
-static const char * const reserved1_groups[] = {
- "gpio1",
-};
-static const char * const reserved2_groups[] = {
- "gpio2",
-};
-static const char * const reserved3_groups[] = {
- "gpio3",
-};
static const char * const qup9_groups[] = {
"gpio4", "gpio5", "gpio6", "gpio7",
};
@@ -812,18 +1112,9 @@
"gpio4", "gpio5", "gpio51", "gpio52", "gpio62", "gpio63", "gpio90",
"gpio91",
};
-static const char * const reserved4_groups[] = {
- "gpio4",
-};
-static const char * const reserved5_groups[] = {
- "gpio5",
-};
static const char * const ddr_pxi0_groups[] = {
"gpio6", "gpio7",
};
-static const char * const reserved6_groups[] = {
- "gpio6",
-};
static const char * const ddr_bist_groups[] = {
"gpio7", "gpio8", "gpio9", "gpio10",
};
@@ -836,9 +1127,6 @@
static const char * const atest_usb1_groups[] = {
"gpio7",
};
-static const char * const reserved7_groups[] = {
- "gpio7",
-};
static const char * const qup_l4_groups[] = {
"gpio8", "gpio35", "gpio105", "gpio123",
};
@@ -851,9 +1139,6 @@
static const char * const ddr_pxi1_groups[] = {
"gpio8", "gpio9",
};
-static const char * const reserved8_groups[] = {
- "gpio8",
-};
static const char * const qup_l5_groups[] = {
"gpio9", "gpio36", "gpio106", "gpio124",
};
@@ -863,9 +1148,6 @@
static const char * const atest_usb12_groups[] = {
"gpio9",
};
-static const char * const reserved9_groups[] = {
- "gpio9",
-};
static const char * const mdp_vsync_groups[] = {
"gpio10", "gpio11", "gpio12", "gpio97", "gpio98",
};
@@ -881,9 +1163,6 @@
static const char * const ddr_pxi2_groups[] = {
"gpio10", "gpio11",
};
-static const char * const reserved10_groups[] = {
- "gpio10",
-};
static const char * const edp_lcd_groups[] = {
"gpio11",
};
@@ -896,1191 +1175,107 @@
static const char * const atest_usb10_groups[] = {
"gpio11",
};
-static const char * const reserved11_groups[] = {
- "gpio11",
-};
static const char * const m_voc_groups[] = {
"gpio12",
};
static const char * const tsif1_sync_groups[] = {
"gpio12",
};
-static const char * const ddr_pxi3_groups[] = {
- "gpio12", "gpio13",
-};
-static const char * const reserved12_groups[] = {
- "gpio12",
-};
-static const char * const cam_mclk_groups[] = {
- "gpio13", "gpio14", "gpio15", "gpio16",
-};
-static const char * const pll_bypassnl_groups[] = {
- "gpio13",
-};
-static const char * const qdss_gpio0_groups[] = {
- "gpio13", "gpio117",
-};
-static const char * const reserved13_groups[] = {
- "gpio13",
-};
-static const char * const pll_reset_groups[] = {
- "gpio14",
-};
-static const char * const qdss_gpio1_groups[] = {
- "gpio14", "gpio118",
-};
-static const char * const reserved14_groups[] = {
- "gpio14",
-};
-static const char * const qdss_gpio2_groups[] = {
- "gpio15", "gpio119",
-};
-static const char * const reserved15_groups[] = {
- "gpio15",
-};
-static const char * const qdss_gpio3_groups[] = {
- "gpio16", "gpio120",
-};
-static const char * const reserved16_groups[] = {
- "gpio16",
-};
-static const char * const cci_i2c_groups[] = {
- "gpio17", "gpio18", "gpio19", "gpio20",
-};
-static const char * const qup1_groups[] = {
- "gpio17", "gpio18", "gpio19", "gpio20",
-};
-static const char * const qdss_gpio4_groups[] = {
- "gpio17", "gpio121",
-};
-static const char * const reserved17_groups[] = {
- "gpio17",
-};
-static const char * const qdss_gpio5_groups[] = {
- "gpio18", "gpio122",
-};
-static const char * const reserved18_groups[] = {
- "gpio18",
-};
-static const char * const qdss_gpio6_groups[] = {
- "gpio19", "gpio41",
-};
-static const char * const reserved19_groups[] = {
- "gpio19",
-};
-static const char * const qdss_gpio7_groups[] = {
- "gpio20", "gpio42",
-};
-static const char * const reserved20_groups[] = {
- "gpio20",
-};
-static const char * const cci_timer0_groups[] = {
- "gpio21",
-};
-static const char * const gcc_gp2_groups[] = {
- "gpio21", "gpio58",
-};
-static const char * const qdss_gpio8_groups[] = {
- "gpio21", "gpio75",
-};
-static const char * const reserved21_groups[] = {
- "gpio21",
-};
-static const char * const cci_timer1_groups[] = {
- "gpio22",
-};
-static const char * const gcc_gp3_groups[] = {
- "gpio22", "gpio59",
-};
-static const char * const qdss_gpio_groups[] = {
- "gpio22", "gpio30", "gpio123", "gpio124",
-};
-static const char * const reserved22_groups[] = {
- "gpio22",
-};
-static const char * const cci_timer2_groups[] = {
- "gpio23",
-};
-static const char * const qdss_gpio9_groups[] = {
- "gpio23", "gpio76",
-};
-static const char * const reserved23_groups[] = {
- "gpio23",
-};
-static const char * const cci_timer3_groups[] = {
- "gpio24",
-};
-static const char * const cci_async_groups[] = {
- "gpio24", "gpio25", "gpio26",
-};
-static const char * const qdss_gpio10_groups[] = {
- "gpio24", "gpio77",
-};
-static const char * const reserved24_groups[] = {
- "gpio24",
-};
-static const char * const cci_timer4_groups[] = {
- "gpio25",
-};
-static const char * const qdss_gpio11_groups[] = {
- "gpio25", "gpio79",
-};
-static const char * const reserved25_groups[] = {
- "gpio25",
-};
-static const char * const qdss_gpio12_groups[] = {
- "gpio26", "gpio80",
-};
-static const char * const reserved26_groups[] = {
- "gpio26",
-};
-static const char * const qup2_groups[] = {
- "gpio27", "gpio28", "gpio29", "gpio30",
-};
-static const char * const qdss_gpio13_groups[] = {
- "gpio27", "gpio93",
-};
-static const char * const reserved27_groups[] = {
- "gpio27",
-};
-static const char * const qdss_gpio14_groups[] = {
- "gpio28", "gpio43",
-};
-static const char * const reserved28_groups[] = {
- "gpio28",
-};
-static const char * const phase_flag1_groups[] = {
- "gpio29",
-};
-static const char * const qdss_gpio15_groups[] = {
- "gpio29", "gpio44",
-};
-static const char * const reserved29_groups[] = {
- "gpio29",
-};
-static const char * const phase_flag2_groups[] = {
- "gpio30",
-};
-static const char * const reserved30_groups[] = {
- "gpio30",
-};
-static const char * const qup11_groups[] = {
- "gpio31", "gpio32", "gpio33", "gpio34",
-};
-static const char * const qup14_groups[] = {
- "gpio31", "gpio32", "gpio33", "gpio34",
-};
-static const char * const reserved96_groups[] = {
- "gpio96",
-};
-static const char * const ldo_en_groups[] = {
- "gpio97",
-};
-static const char * const reserved97_groups[] = {
- "gpio97",
-};
-static const char * const ldo_update_groups[] = {
- "gpio98",
-};
-static const char * const reserved98_groups[] = {
- "gpio98",
-};
-static const char * const phase_flag14_groups[] = {
- "gpio99",
-};
-static const char * const reserved99_groups[] = {
- "gpio99",
-};
-static const char * const phase_flag15_groups[] = {
- "gpio100",
-};
-static const char * const reserved100_groups[] = {
- "gpio100",
-};
-static const char * const reserved101_groups[] = {
- "gpio101",
-};
-static const char * const pci_e1_groups[] = {
- "gpio102", "gpio103",
-};
-static const char * const prng_rosc_groups[] = {
- "gpio102",
-};
-static const char * const reserved102_groups[] = {
- "gpio102",
-};
-static const char * const phase_flag5_groups[] = {
- "gpio103",
-};
-static const char * const reserved103_groups[] = {
- "gpio103",
-};
-static const char * const reserved104_groups[] = {
- "gpio104",
-};
-static const char * const uim2_data_groups[] = {
- "gpio105",
-};
-static const char * const qup13_groups[] = {
- "gpio105", "gpio106", "gpio107", "gpio108",
-};
-static const char * const reserved105_groups[] = {
- "gpio105",
-};
-static const char * const uim2_clk_groups[] = {
- "gpio106",
-};
-static const char * const reserved106_groups[] = {
- "gpio106",
-};
-static const char * const uim2_reset_groups[] = {
- "gpio107",
-};
-static const char * const reserved107_groups[] = {
- "gpio107",
-};
-static const char * const uim2_present_groups[] = {
- "gpio108",
-};
-static const char * const reserved108_groups[] = {
- "gpio108",
-};
-static const char * const uim1_data_groups[] = {
- "gpio109",
-};
-static const char * const reserved109_groups[] = {
- "gpio109",
-};
-static const char * const uim1_clk_groups[] = {
- "gpio110",
-};
-static const char * const reserved110_groups[] = {
- "gpio110",
-};
-static const char * const uim1_reset_groups[] = {
- "gpio111",
-};
-static const char * const reserved111_groups[] = {
- "gpio111",
-};
-static const char * const uim1_present_groups[] = {
- "gpio112",
-};
-static const char * const reserved112_groups[] = {
- "gpio112",
-};
-static const char * const uim_batt_groups[] = {
- "gpio113",
-};
-static const char * const edp_hot_groups[] = {
- "gpio113",
-};
-static const char * const reserved113_groups[] = {
- "gpio113",
-};
-static const char * const nav_pps_groups[] = {
- "gpio114", "gpio114", "gpio115", "gpio115", "gpio128", "gpio128",
- "gpio129", "gpio129", "gpio143", "gpio143",
-};
-static const char * const reserved114_groups[] = {
- "gpio114",
-};
-static const char * const reserved115_groups[] = {
- "gpio115",
-};
-static const char * const reserved116_groups[] = {
- "gpio116",
-};
-static const char * const atest_char_groups[] = {
- "gpio117",
-};
-static const char * const reserved117_groups[] = {
- "gpio117",
-};
-static const char * const adsp_ext_groups[] = {
- "gpio118",
-};
-static const char * const atest_char3_groups[] = {
- "gpio118",
-};
-static const char * const reserved118_groups[] = {
- "gpio118",
-};
-static const char * const atest_char2_groups[] = {
- "gpio119",
-};
-static const char * const reserved119_groups[] = {
- "gpio119",
-};
-static const char * const atest_char1_groups[] = {
- "gpio120",
-};
-static const char * const reserved120_groups[] = {
- "gpio120",
-};
-static const char * const atest_char0_groups[] = {
- "gpio121",
-};
-static const char * const reserved121_groups[] = {
- "gpio121",
-};
-static const char * const reserved122_groups[] = {
- "gpio122",
-};
-static const char * const reserved123_groups[] = {
- "gpio123",
-};
-static const char * const reserved124_groups[] = {
- "gpio124",
-};
-static const char * const reserved125_groups[] = {
- "gpio125",
-};
-static const char * const reserved126_groups[] = {
- "gpio126",
-};
-static const char * const reserved127_groups[] = {
- "gpio127",
-};
-static const char * const reserved128_groups[] = {
- "gpio128",
-};
-static const char * const reserved129_groups[] = {
- "gpio129",
-};
-static const char * const qlink_request_groups[] = {
- "gpio130",
-};
-static const char * const reserved130_groups[] = {
- "gpio130",
-};
-static const char * const qlink_enable_groups[] = {
- "gpio131",
-};
-static const char * const reserved131_groups[] = {
- "gpio131",
-};
-static const char * const reserved132_groups[] = {
- "gpio132",
-};
-static const char * const reserved133_groups[] = {
- "gpio133",
-};
-static const char * const reserved134_groups[] = {
- "gpio134",
-};
-static const char * const pa_indicator_groups[] = {
- "gpio135",
-};
-static const char * const reserved135_groups[] = {
- "gpio135",
-};
-static const char * const reserved136_groups[] = {
- "gpio136",
-};
-static const char * const phase_flag26_groups[] = {
- "gpio137",
-};
-static const char * const reserved137_groups[] = {
- "gpio137",
-};
-static const char * const phase_flag27_groups[] = {
- "gpio138",
-};
-static const char * const reserved138_groups[] = {
- "gpio138",
-};
-static const char * const phase_flag28_groups[] = {
- "gpio139",
-};
-static const char * const reserved139_groups[] = {
- "gpio139",
-};
-static const char * const phase_flag6_groups[] = {
- "gpio140",
-};
-static const char * const reserved140_groups[] = {
- "gpio140",
-};
-static const char * const phase_flag29_groups[] = {
- "gpio141",
-};
-static const char * const reserved141_groups[] = {
- "gpio141",
-};
-static const char * const phase_flag30_groups[] = {
- "gpio142",
-};
-static const char * const reserved142_groups[] = {
- "gpio142",
-};
-static const char * const phase_flag31_groups[] = {
- "gpio143",
-};
-static const char * const reserved143_groups[] = {
- "gpio143",
-};
-static const char * const mss_lte_groups[] = {
- "gpio144", "gpio145",
-};
-static const char * const reserved144_groups[] = {
- "gpio144",
-};
-static const char * const reserved145_groups[] = {
- "gpio145",
-};
-static const char * const reserved146_groups[] = {
- "gpio146",
-};
-static const char * const reserved147_groups[] = {
- "gpio147",
-};
-static const char * const reserved148_groups[] = {
- "gpio148",
-};
-static const char * const reserved149_groups[] = {
- "gpio149", "gpio149",
-};
-static const char * const reserved31_groups[] = {
- "gpio31",
-};
-static const char * const reserved32_groups[] = {
- "gpio32",
-};
-static const char * const reserved33_groups[] = {
- "gpio33",
-};
-static const char * const reserved34_groups[] = {
- "gpio34",
-};
-static const char * const pci_e0_groups[] = {
- "gpio35", "gpio36",
-};
-static const char * const jitter_bist_groups[] = {
- "gpio35",
-};
-static const char * const reserved35_groups[] = {
- "gpio35",
-};
-static const char * const pll_bist_groups[] = {
- "gpio36",
-};
-static const char * const atest_tsens_groups[] = {
- "gpio36",
-};
-static const char * const reserved36_groups[] = {
- "gpio36",
-};
-static const char * const agera_pll_groups[] = {
- "gpio37",
-};
-static const char * const reserved37_groups[] = {
- "gpio37",
-};
-static const char * const usb_phy_groups[] = {
- "gpio38",
-};
-static const char * const reserved38_groups[] = {
- "gpio38",
-};
-static const char * const lpass_slimbus_groups[] = {
- "gpio39", "gpio70", "gpio71", "gpio72",
-};
-static const char * const reserved39_groups[] = {
- "gpio39",
-};
-static const char * const sd_write_groups[] = {
- "gpio40",
-};
-static const char * const tsif1_error_groups[] = {
- "gpio40",
-};
-static const char * const reserved40_groups[] = {
- "gpio40",
-};
-static const char * const qup3_groups[] = {
- "gpio41", "gpio42", "gpio43", "gpio44",
-};
-static const char * const reserved41_groups[] = {
- "gpio41",
-};
-static const char * const reserved42_groups[] = {
- "gpio42",
-};
-static const char * const reserved43_groups[] = {
- "gpio43",
-};
-static const char * const reserved44_groups[] = {
- "gpio44",
-};
-static const char * const qup6_groups[] = {
- "gpio45", "gpio46", "gpio47", "gpio48",
-};
-static const char * const reserved45_groups[] = {
- "gpio45",
-};
-static const char * const reserved46_groups[] = {
- "gpio46",
-};
-static const char * const reserved47_groups[] = {
- "gpio47",
-};
-static const char * const reserved48_groups[] = {
- "gpio48",
-};
-static const char * const qup12_groups[] = {
- "gpio49", "gpio50", "gpio51", "gpio52",
-};
-static const char * const reserved49_groups[] = {
- "gpio49",
-};
-static const char * const reserved50_groups[] = {
- "gpio50",
-};
-static const char * const reserved51_groups[] = {
- "gpio51",
-};
-static const char * const phase_flag16_groups[] = {
- "gpio52",
-};
-static const char * const reserved52_groups[] = {
- "gpio52",
-};
-static const char * const qup10_groups[] = {
- "gpio53", "gpio54", "gpio55", "gpio56",
-};
-static const char * const phase_flag11_groups[] = {
- "gpio53",
-};
-static const char * const reserved53_groups[] = {
- "gpio53",
-};
-static const char * const phase_flag12_groups[] = {
- "gpio54",
-};
-static const char * const reserved54_groups[] = {
- "gpio54",
-};
-static const char * const phase_flag13_groups[] = {
- "gpio55",
-};
-static const char * const reserved55_groups[] = {
- "gpio55",
-};
-static const char * const phase_flag17_groups[] = {
- "gpio56",
-};
-static const char * const reserved56_groups[] = {
- "gpio56",
-};
-static const char * const qua_mi2s_groups[] = {
- "gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63",
-};
-static const char * const gcc_gp1_groups[] = {
- "gpio57", "gpio78",
-};
-static const char * const phase_flag18_groups[] = {
- "gpio57",
-};
-static const char * const reserved57_groups[] = {
- "gpio57",
-};
-static const char * const phase_flag19_groups[] = {
- "gpio58",
-};
-static const char * const reserved58_groups[] = {
- "gpio58",
-};
-static const char * const phase_flag20_groups[] = {
- "gpio59",
-};
-static const char * const reserved59_groups[] = {
- "gpio59",
-};
-static const char * const cri_trng0_groups[] = {
- "gpio60",
-};
-static const char * const phase_flag21_groups[] = {
- "gpio60",
-};
-static const char * const reserved60_groups[] = {
- "gpio60",
-};
-static const char * const cri_trng1_groups[] = {
- "gpio61",
-};
-static const char * const phase_flag22_groups[] = {
- "gpio61",
-};
-static const char * const reserved61_groups[] = {
- "gpio61",
-};
-static const char * const cri_trng_groups[] = {
- "gpio62",
-};
-static const char * const phase_flag23_groups[] = {
- "gpio62",
-};
-static const char * const reserved62_groups[] = {
- "gpio62",
-};
-static const char * const phase_flag24_groups[] = {
- "gpio63",
-};
-static const char * const reserved63_groups[] = {
- "gpio63",
-};
-static const char * const pri_mi2s_groups[] = {
- "gpio64", "gpio65", "gpio67", "gpio68",
-};
-static const char * const sp_cmu_groups[] = {
- "gpio64",
-};
-static const char * const phase_flag25_groups[] = {
- "gpio64",
-};
-static const char * const reserved64_groups[] = {
- "gpio64",
-};
-static const char * const qup8_groups[] = {
- "gpio65", "gpio66", "gpio67", "gpio68",
-};
-static const char * const reserved65_groups[] = {
- "gpio65",
-};
-static const char * const pri_mi2s_ws_groups[] = {
- "gpio66",
-};
-static const char * const reserved66_groups[] = {
- "gpio66",
-};
-static const char * const reserved67_groups[] = {
- "gpio67",
-};
-static const char * const reserved68_groups[] = {
- "gpio68",
-};
-static const char * const spkr_i2s_groups[] = {
- "gpio69", "gpio70", "gpio71", "gpio72",
-};
-static const char * const audio_ref_groups[] = {
- "gpio69",
-};
-static const char * const reserved69_groups[] = {
- "gpio69",
-};
-static const char * const reserved70_groups[] = {
- "gpio70",
-};
-static const char * const tsense_pwm1_groups[] = {
- "gpio71",
-};
-static const char * const tsense_pwm2_groups[] = {
- "gpio71",
-};
-static const char * const reserved71_groups[] = {
- "gpio71",
-};
-static const char * const reserved72_groups[] = {
- "gpio72",
-};
-static const char * const btfm_slimbus_groups[] = {
- "gpio73", "gpio74",
-};
-static const char * const atest_usb2_groups[] = {
- "gpio73",
-};
-static const char * const reserved73_groups[] = {
- "gpio73",
-};
-static const char * const ter_mi2s_groups[] = {
- "gpio74", "gpio75", "gpio76", "gpio77", "gpio78",
-};
-static const char * const phase_flag7_groups[] = {
- "gpio74",
-};
-static const char * const atest_usb23_groups[] = {
- "gpio74",
-};
-static const char * const reserved74_groups[] = {
- "gpio74",
-};
-static const char * const phase_flag8_groups[] = {
- "gpio75",
-};
-static const char * const atest_usb22_groups[] = {
- "gpio75",
-};
-static const char * const reserved75_groups[] = {
- "gpio75",
-};
-static const char * const phase_flag9_groups[] = {
- "gpio76",
-};
-static const char * const atest_usb21_groups[] = {
- "gpio76",
-};
-static const char * const reserved76_groups[] = {
- "gpio76",
-};
-static const char * const phase_flag4_groups[] = {
- "gpio77",
-};
-static const char * const atest_usb20_groups[] = {
- "gpio77",
-};
-static const char * const reserved77_groups[] = {
- "gpio77",
-};
-static const char * const reserved78_groups[] = {
- "gpio78",
-};
-static const char * const sec_mi2s_groups[] = {
- "gpio79", "gpio80", "gpio81", "gpio82", "gpio83",
-};
-static const char * const reserved79_groups[] = {
- "gpio79",
-};
-static const char * const reserved80_groups[] = {
- "gpio80",
-};
-static const char * const qup15_groups[] = {
- "gpio81", "gpio82", "gpio83", "gpio84",
-};
-static const char * const reserved81_groups[] = {
- "gpio81",
-};
-static const char * const reserved82_groups[] = {
- "gpio82",
-};
-static const char * const reserved83_groups[] = {
- "gpio83",
-};
-static const char * const reserved84_groups[] = {
- "gpio84",
-};
-static const char * const qup5_groups[] = {
- "gpio85", "gpio86", "gpio87", "gpio88",
-};
-static const char * const reserved85_groups[] = {
- "gpio85",
-};
-static const char * const reserved86_groups[] = {
- "gpio86",
-};
-static const char * const reserved87_groups[] = {
- "gpio87",
-};
-static const char * const reserved88_groups[] = {
- "gpio88",
-};
-static const char * const tsif1_clk_groups[] = {
- "gpio89",
-};
-static const char * const qup4_groups[] = {
- "gpio89", "gpio90", "gpio91", "gpio92",
-};
-static const char * const tgu_ch3_groups[] = {
- "gpio89",
-};
-static const char * const phase_flag10_groups[] = {
- "gpio89",
-};
-static const char * const reserved89_groups[] = {
- "gpio89",
-};
-static const char * const tsif1_en_groups[] = {
- "gpio90",
-};
-static const char * const mdp_vsync0_groups[] = {
- "gpio90",
-};
-static const char * const mdp_vsync1_groups[] = {
- "gpio90",
-};
-static const char * const mdp_vsync2_groups[] = {
- "gpio90",
-};
-static const char * const mdp_vsync3_groups[] = {
- "gpio90",
-};
-static const char * const tgu_ch0_groups[] = {
- "gpio90",
-};
-static const char * const phase_flag0_groups[] = {
- "gpio90",
-};
-static const char * const reserved90_groups[] = {
- "gpio90",
-};
-static const char * const tsif1_data_groups[] = {
- "gpio91",
-};
-static const char * const sdc4_cmd_groups[] = {
- "gpio91",
-};
-static const char * const tgu_ch1_groups[] = {
- "gpio91",
-};
-static const char * const reserved91_groups[] = {
- "gpio91",
-};
-static const char * const tsif2_error_groups[] = {
- "gpio92",
-};
-static const char * const sdc43_groups[] = {
- "gpio92",
-};
-static const char * const vfr_1_groups[] = {
- "gpio92",
-};
-static const char * const tgu_ch2_groups[] = {
- "gpio92",
-};
-static const char * const reserved92_groups[] = {
- "gpio92",
-};
-static const char * const tsif2_clk_groups[] = {
- "gpio93",
-};
-static const char * const sdc4_clk_groups[] = {
- "gpio93",
-};
-static const char * const qup7_groups[] = {
- "gpio93", "gpio94", "gpio95", "gpio96",
-};
-static const char * const reserved93_groups[] = {
- "gpio93",
-};
-static const char * const tsif2_en_groups[] = {
- "gpio94",
-};
-static const char * const sdc42_groups[] = {
- "gpio94",
-};
-static const char * const reserved94_groups[] = {
- "gpio94",
-};
-static const char * const tsif2_data_groups[] = {
- "gpio95",
-};
-static const char * const sdc41_groups[] = {
- "gpio95",
-};
-static const char * const reserved95_groups[] = {
- "gpio95",
-};
-static const char * const tsif2_sync_groups[] = {
- "gpio96",
-};
-static const char * const sdc40_groups[] = {
- "gpio96",
-};
-static const char * const phase_flag3_groups[] = {
- "gpio96",
-};
static const struct msm_function sdm845_functions[] = {
- FUNCTION(gpio),
- FUNCTION(qup0),
- FUNCTION(reserved0),
- FUNCTION(reserved1),
- FUNCTION(reserved2),
- FUNCTION(reserved3),
- FUNCTION(qup9),
- FUNCTION(qdss_cti),
- FUNCTION(reserved4),
- FUNCTION(reserved5),
- FUNCTION(ddr_pxi0),
- FUNCTION(reserved6),
- FUNCTION(ddr_bist),
- FUNCTION(atest_tsens2),
- FUNCTION(vsense_trigger),
- FUNCTION(atest_usb1),
- FUNCTION(reserved7),
- FUNCTION(qup_l4),
- FUNCTION(wlan1_adc1),
- FUNCTION(atest_usb13),
- FUNCTION(ddr_pxi1),
- FUNCTION(reserved8),
- FUNCTION(qup_l5),
- FUNCTION(wlan1_adc0),
- FUNCTION(atest_usb12),
- FUNCTION(reserved9),
- FUNCTION(mdp_vsync),
- FUNCTION(qup_l6),
- FUNCTION(wlan2_adc1),
- FUNCTION(atest_usb11),
- FUNCTION(ddr_pxi2),
- FUNCTION(reserved10),
- FUNCTION(edp_lcd),
- FUNCTION(dbg_out),
- FUNCTION(wlan2_adc0),
- FUNCTION(atest_usb10),
- FUNCTION(reserved11),
- FUNCTION(m_voc),
- FUNCTION(tsif1_sync),
FUNCTION(ddr_pxi3),
- FUNCTION(reserved12),
FUNCTION(cam_mclk),
FUNCTION(pll_bypassnl),
FUNCTION(qdss_gpio0),
- FUNCTION(reserved13),
FUNCTION(pll_reset),
FUNCTION(qdss_gpio1),
- FUNCTION(reserved14),
FUNCTION(qdss_gpio2),
- FUNCTION(reserved15),
FUNCTION(qdss_gpio3),
- FUNCTION(reserved16),
FUNCTION(cci_i2c),
FUNCTION(qup1),
FUNCTION(qdss_gpio4),
- FUNCTION(reserved17),
FUNCTION(qdss_gpio5),
- FUNCTION(reserved18),
FUNCTION(qdss_gpio6),
- FUNCTION(reserved19),
FUNCTION(qdss_gpio7),
- FUNCTION(reserved20),
FUNCTION(cci_timer0),
FUNCTION(gcc_gp2),
FUNCTION(qdss_gpio8),
- FUNCTION(reserved21),
FUNCTION(cci_timer1),
FUNCTION(gcc_gp3),
FUNCTION(qdss_gpio),
- FUNCTION(reserved22),
FUNCTION(cci_timer2),
FUNCTION(qdss_gpio9),
- FUNCTION(reserved23),
FUNCTION(cci_timer3),
FUNCTION(cci_async),
FUNCTION(qdss_gpio10),
- FUNCTION(reserved24),
FUNCTION(cci_timer4),
FUNCTION(qdss_gpio11),
- FUNCTION(reserved25),
FUNCTION(qdss_gpio12),
- FUNCTION(reserved26),
FUNCTION(qup2),
FUNCTION(qdss_gpio13),
- FUNCTION(reserved27),
FUNCTION(qdss_gpio14),
- FUNCTION(reserved28),
FUNCTION(phase_flag1),
FUNCTION(qdss_gpio15),
- FUNCTION(reserved29),
FUNCTION(phase_flag2),
- FUNCTION(reserved30),
FUNCTION(qup11),
FUNCTION(qup14),
- FUNCTION(reserved96),
- FUNCTION(ldo_en),
- FUNCTION(reserved97),
- FUNCTION(ldo_update),
- FUNCTION(reserved98),
- FUNCTION(phase_flag14),
- FUNCTION(reserved99),
- FUNCTION(phase_flag15),
- FUNCTION(reserved100),
- FUNCTION(reserved101),
- FUNCTION(pci_e1),
- FUNCTION(prng_rosc),
- FUNCTION(reserved102),
- FUNCTION(phase_flag5),
- FUNCTION(reserved103),
- FUNCTION(reserved104),
- FUNCTION(uim2_data),
- FUNCTION(qup13),
- FUNCTION(reserved105),
- FUNCTION(uim2_clk),
- FUNCTION(reserved106),
- FUNCTION(uim2_reset),
- FUNCTION(reserved107),
- FUNCTION(uim2_present),
- FUNCTION(reserved108),
- FUNCTION(uim1_data),
- FUNCTION(reserved109),
- FUNCTION(uim1_clk),
- FUNCTION(reserved110),
- FUNCTION(uim1_reset),
- FUNCTION(reserved111),
- FUNCTION(uim1_present),
- FUNCTION(reserved112),
- FUNCTION(uim_batt),
- FUNCTION(edp_hot),
- FUNCTION(reserved113),
- FUNCTION(nav_pps),
- FUNCTION(reserved114),
- FUNCTION(reserved115),
- FUNCTION(reserved116),
- FUNCTION(atest_char),
- FUNCTION(reserved117),
- FUNCTION(adsp_ext),
- FUNCTION(atest_char3),
- FUNCTION(reserved118),
- FUNCTION(atest_char2),
- FUNCTION(reserved119),
- FUNCTION(atest_char1),
- FUNCTION(reserved120),
- FUNCTION(atest_char0),
- FUNCTION(reserved121),
- FUNCTION(reserved122),
- FUNCTION(reserved123),
- FUNCTION(reserved124),
- FUNCTION(reserved125),
- FUNCTION(reserved126),
- FUNCTION(reserved127),
- FUNCTION(reserved128),
- FUNCTION(reserved129),
- FUNCTION(qlink_request),
- FUNCTION(reserved130),
- FUNCTION(qlink_enable),
- FUNCTION(reserved131),
- FUNCTION(reserved132),
- FUNCTION(reserved133),
- FUNCTION(reserved134),
- FUNCTION(pa_indicator),
- FUNCTION(reserved135),
- FUNCTION(reserved136),
- FUNCTION(phase_flag26),
- FUNCTION(reserved137),
- FUNCTION(phase_flag27),
- FUNCTION(reserved138),
- FUNCTION(phase_flag28),
- FUNCTION(reserved139),
- FUNCTION(phase_flag6),
- FUNCTION(reserved140),
- FUNCTION(phase_flag29),
- FUNCTION(reserved141),
- FUNCTION(phase_flag30),
- FUNCTION(reserved142),
- FUNCTION(phase_flag31),
- FUNCTION(reserved143),
- FUNCTION(mss_lte),
- FUNCTION(reserved144),
- FUNCTION(reserved145),
- FUNCTION(reserved146),
- FUNCTION(reserved147),
- FUNCTION(reserved148),
- FUNCTION(reserved149),
- FUNCTION(reserved31),
- FUNCTION(reserved32),
- FUNCTION(reserved33),
- FUNCTION(reserved34),
FUNCTION(pci_e0),
FUNCTION(jitter_bist),
- FUNCTION(reserved35),
FUNCTION(pll_bist),
FUNCTION(atest_tsens),
- FUNCTION(reserved36),
FUNCTION(agera_pll),
- FUNCTION(reserved37),
FUNCTION(usb_phy),
- FUNCTION(reserved38),
FUNCTION(lpass_slimbus),
- FUNCTION(reserved39),
FUNCTION(sd_write),
FUNCTION(tsif1_error),
- FUNCTION(reserved40),
FUNCTION(qup3),
- FUNCTION(reserved41),
- FUNCTION(reserved42),
- FUNCTION(reserved43),
- FUNCTION(reserved44),
FUNCTION(qup6),
- FUNCTION(reserved45),
- FUNCTION(reserved46),
- FUNCTION(reserved47),
- FUNCTION(reserved48),
FUNCTION(qup12),
- FUNCTION(reserved49),
- FUNCTION(reserved50),
- FUNCTION(reserved51),
FUNCTION(phase_flag16),
- FUNCTION(reserved52),
FUNCTION(qup10),
FUNCTION(phase_flag11),
- FUNCTION(reserved53),
FUNCTION(phase_flag12),
- FUNCTION(reserved54),
FUNCTION(phase_flag13),
- FUNCTION(reserved55),
FUNCTION(phase_flag17),
- FUNCTION(reserved56),
FUNCTION(qua_mi2s),
FUNCTION(gcc_gp1),
FUNCTION(phase_flag18),
- FUNCTION(reserved57),
FUNCTION(phase_flag19),
- FUNCTION(reserved58),
FUNCTION(phase_flag20),
- FUNCTION(reserved59),
FUNCTION(cri_trng0),
FUNCTION(phase_flag21),
- FUNCTION(reserved60),
FUNCTION(cri_trng1),
FUNCTION(phase_flag22),
- FUNCTION(reserved61),
FUNCTION(cri_trng),
FUNCTION(phase_flag23),
- FUNCTION(reserved62),
FUNCTION(phase_flag24),
- FUNCTION(reserved63),
FUNCTION(pri_mi2s),
FUNCTION(sp_cmu),
FUNCTION(phase_flag25),
- FUNCTION(reserved64),
FUNCTION(qup8),
- FUNCTION(reserved65),
FUNCTION(pri_mi2s_ws),
- FUNCTION(reserved66),
- FUNCTION(reserved67),
- FUNCTION(reserved68),
FUNCTION(spkr_i2s),
FUNCTION(audio_ref),
- FUNCTION(reserved69),
- FUNCTION(reserved70),
FUNCTION(tsense_pwm1),
FUNCTION(tsense_pwm2),
- FUNCTION(reserved71),
- FUNCTION(reserved72),
FUNCTION(btfm_slimbus),
FUNCTION(atest_usb2),
- FUNCTION(reserved73),
FUNCTION(ter_mi2s),
FUNCTION(phase_flag7),
FUNCTION(atest_usb23),
- FUNCTION(reserved74),
FUNCTION(phase_flag8),
FUNCTION(atest_usb22),
- FUNCTION(reserved75),
FUNCTION(phase_flag9),
FUNCTION(atest_usb21),
- FUNCTION(reserved76),
FUNCTION(phase_flag4),
FUNCTION(atest_usb20),
- FUNCTION(reserved77),
- FUNCTION(reserved78),
FUNCTION(sec_mi2s),
- FUNCTION(reserved79),
- FUNCTION(reserved80),
FUNCTION(qup15),
- FUNCTION(reserved81),
- FUNCTION(reserved82),
- FUNCTION(reserved83),
- FUNCTION(reserved84),
FUNCTION(qup5),
- FUNCTION(reserved85),
- FUNCTION(reserved86),
- FUNCTION(reserved87),
- FUNCTION(reserved88),
FUNCTION(tsif1_clk),
FUNCTION(qup4),
FUNCTION(tgu_ch3),
FUNCTION(phase_flag10),
- FUNCTION(reserved89),
FUNCTION(tsif1_en),
FUNCTION(mdp_vsync0),
FUNCTION(mdp_vsync1),
@@ -2088,293 +1283,347 @@
FUNCTION(mdp_vsync3),
FUNCTION(tgu_ch0),
FUNCTION(phase_flag0),
- FUNCTION(reserved90),
FUNCTION(tsif1_data),
FUNCTION(sdc4_cmd),
FUNCTION(tgu_ch1),
- FUNCTION(reserved91),
FUNCTION(tsif2_error),
FUNCTION(sdc43),
FUNCTION(vfr_1),
FUNCTION(tgu_ch2),
- FUNCTION(reserved92),
FUNCTION(tsif2_clk),
FUNCTION(sdc4_clk),
FUNCTION(qup7),
- FUNCTION(reserved93),
FUNCTION(tsif2_en),
FUNCTION(sdc42),
- FUNCTION(reserved94),
FUNCTION(tsif2_data),
FUNCTION(sdc41),
- FUNCTION(reserved95),
FUNCTION(tsif2_sync),
FUNCTION(sdc40),
FUNCTION(phase_flag3),
+ FUNCTION(ldo_en),
+ FUNCTION(ldo_update),
+ FUNCTION(phase_flag14),
+ FUNCTION(phase_flag15),
+ FUNCTION(pci_e1),
+ FUNCTION(prng_rosc),
+ FUNCTION(phase_flag5),
+ FUNCTION(uim2_data),
+ FUNCTION(qup13),
+ FUNCTION(uim2_clk),
+ FUNCTION(uim2_reset),
+ FUNCTION(uim2_present),
+ FUNCTION(uim1_data),
+ FUNCTION(uim1_clk),
+ FUNCTION(uim1_reset),
+ FUNCTION(uim1_present),
+ FUNCTION(uim_batt),
+ FUNCTION(edp_hot),
+ FUNCTION(nav_pps),
+ FUNCTION(atest_char),
+ FUNCTION(adsp_ext),
+ FUNCTION(atest_char3),
+ FUNCTION(atest_char2),
+ FUNCTION(atest_char1),
+ FUNCTION(atest_char0),
+ FUNCTION(qlink_request),
+ FUNCTION(qlink_enable),
+ FUNCTION(pa_indicator),
+ FUNCTION(phase_flag26),
+ FUNCTION(phase_flag27),
+ FUNCTION(phase_flag28),
+ FUNCTION(phase_flag6),
+ FUNCTION(phase_flag29),
+ FUNCTION(phase_flag30),
+ FUNCTION(phase_flag31),
+ FUNCTION(mss_lte),
+ FUNCTION(qup0),
+ FUNCTION(gpio),
+ FUNCTION(qup9),
+ FUNCTION(qdss_cti),
+ FUNCTION(ddr_pxi0),
+ FUNCTION(ddr_bist),
+ FUNCTION(atest_tsens2),
+ FUNCTION(vsense_trigger),
+ FUNCTION(atest_usb1),
+ FUNCTION(qup_l4),
+ FUNCTION(wlan1_adc1),
+ FUNCTION(atest_usb13),
+ FUNCTION(ddr_pxi1),
+ FUNCTION(qup_l5),
+ FUNCTION(wlan1_adc0),
+ FUNCTION(atest_usb12),
+ FUNCTION(mdp_vsync),
+ FUNCTION(qup_l6),
+ FUNCTION(wlan2_adc1),
+ FUNCTION(atest_usb11),
+ FUNCTION(ddr_pxi2),
+ FUNCTION(edp_lcd),
+ FUNCTION(dbg_out),
+ FUNCTION(wlan2_adc0),
+ FUNCTION(atest_usb10),
+ FUNCTION(m_voc),
+ FUNCTION(tsif1_sync),
};
+/* Every pin is maintained as a single group, and missing or non-existing pin
+ * would be maintained as dummy group to synchronize pin group index with
+ * pin descriptor registered with pinctrl core.
+ * Clients would not be able to request these dummy pin groups.
+ */
static const struct msm_pingroup sdm845_groups[] = {
- PINGROUP(0, NORTH, qup0, NA, reserved0, NA, NA, NA, NA, NA, NA),
- PINGROUP(1, NORTH, qup0, NA, reserved1, NA, NA, NA, NA, NA, NA),
- PINGROUP(2, NORTH, qup0, NA, reserved2, NA, NA, NA, NA, NA, NA),
- PINGROUP(3, NORTH, qup0, NA, reserved3, NA, NA, NA, NA, NA, NA),
- PINGROUP(4, NORTH, qup9, qdss_cti, reserved4, NA, NA, NA, NA, NA, NA),
- PINGROUP(5, NORTH, qup9, qdss_cti, reserved5, NA, NA, NA, NA, NA, NA),
- PINGROUP(6, NORTH, qup9, NA, ddr_pxi0, reserved6, NA, NA, NA, NA, NA),
- PINGROUP(7, NORTH, qup9, ddr_bist, NA, atest_tsens2, vsense_trigger,
- atest_usb1, ddr_pxi0, reserved7, NA),
- PINGROUP(8, NORTH, qup_l4, NA, ddr_bist, NA, NA, wlan1_adc1,
- atest_usb13, ddr_pxi1, reserved8),
- PINGROUP(9, NORTH, qup_l5, ddr_bist, NA, wlan1_adc0, atest_usb12,
- ddr_pxi1, reserved9, NA, NA),
- PINGROUP(10, NORTH, mdp_vsync, qup_l6, ddr_bist, wlan2_adc1,
- atest_usb11, ddr_pxi2, reserved10, NA, NA),
- PINGROUP(11, NORTH, mdp_vsync, edp_lcd, dbg_out, wlan2_adc0,
- atest_usb10, ddr_pxi2, reserved11, NA, NA),
- PINGROUP(12, SOUTH, mdp_vsync, m_voc, tsif1_sync, ddr_pxi3, reserved12,
- NA, NA, NA, NA),
- PINGROUP(13, SOUTH, cam_mclk, pll_bypassnl, qdss_gpio0, ddr_pxi3,
- reserved13, NA, NA, NA, NA),
- PINGROUP(14, SOUTH, cam_mclk, pll_reset, qdss_gpio1, reserved14, NA,
- NA, NA, NA, NA),
- PINGROUP(15, SOUTH, cam_mclk, qdss_gpio2, reserved15, NA, NA, NA, NA,
- NA, NA),
- PINGROUP(16, SOUTH, cam_mclk, qdss_gpio3, reserved16, NA, NA, NA, NA,
- NA, NA),
- PINGROUP(17, SOUTH, cci_i2c, qup1, qdss_gpio4, reserved17, NA, NA, NA,
- NA, NA),
- PINGROUP(18, SOUTH, cci_i2c, qup1, NA, qdss_gpio5, reserved18, NA, NA,
- NA, NA),
- PINGROUP(19, SOUTH, cci_i2c, qup1, NA, qdss_gpio6, reserved19, NA, NA,
- NA, NA),
- PINGROUP(20, SOUTH, cci_i2c, qup1, NA, qdss_gpio7, reserved20, NA, NA,
- NA, NA),
- PINGROUP(21, SOUTH, cci_timer0, gcc_gp2, qdss_gpio8, reserved21, NA,
- NA, NA, NA, NA),
- PINGROUP(22, SOUTH, cci_timer1, gcc_gp3, qdss_gpio, reserved22, NA, NA,
- NA, NA, NA),
- PINGROUP(23, SOUTH, cci_timer2, qdss_gpio9, reserved23, NA, NA, NA, NA,
- NA, NA),
- PINGROUP(24, SOUTH, cci_timer3, cci_async, qdss_gpio10, reserved24, NA,
- NA, NA, NA, NA),
- PINGROUP(25, SOUTH, cci_timer4, cci_async, qdss_gpio11, reserved25, NA,
- NA, NA, NA, NA),
- PINGROUP(26, SOUTH, cci_async, qdss_gpio12, reserved26, NA, NA, NA, NA,
- NA, NA),
- PINGROUP(27, NORTH, qup2, qdss_gpio13, reserved27, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(28, NORTH, qup2, qdss_gpio14, reserved28, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(29, NORTH, qup2, NA, phase_flag1, qdss_gpio15, reserved29, NA,
- NA, NA, NA),
- PINGROUP(30, NORTH, qup2, phase_flag2, qdss_gpio, reserved30, NA, NA,
- NA, NA, NA),
- PINGROUP(31, NORTH, qup11, qup14, reserved31, NA, NA, NA, NA, NA, NA),
- PINGROUP(32, NORTH, qup11, qup14, NA, reserved32, NA, NA, NA, NA, NA),
- PINGROUP(33, NORTH, qup11, qup14, NA, reserved33, NA, NA, NA, NA, NA),
- PINGROUP(34, NORTH, qup11, qup14, NA, reserved34, NA, NA, NA, NA, NA),
- PINGROUP(35, SOUTH, pci_e0, qup_l4, jitter_bist, NA, reserved35, NA,
- NA, NA, NA),
- PINGROUP(36, SOUTH, pci_e0, qup_l5, pll_bist, NA, atest_tsens,
- reserved36, NA, NA, NA),
- PINGROUP(37, SOUTH, qup_l6, agera_pll, NA, reserved37, NA, NA, NA, NA,
- NA),
- PINGROUP(38, NORTH, usb_phy, NA, reserved38, NA, NA, NA, NA, NA, NA),
- PINGROUP(39, NORTH, lpass_slimbus, NA, reserved39, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(40, SOUTH, sd_write, tsif1_error, NA, reserved40, NA, NA, NA,
- NA, NA),
- PINGROUP(41, SOUTH, qup3, NA, qdss_gpio6, reserved41, NA, NA, NA, NA,
- NA),
- PINGROUP(42, SOUTH, qup3, NA, qdss_gpio7, reserved42, NA, NA, NA, NA,
- NA),
- PINGROUP(43, SOUTH, qup3, NA, qdss_gpio14, reserved43, NA, NA, NA, NA,
- NA),
- PINGROUP(44, SOUTH, qup3, NA, qdss_gpio15, reserved44, NA, NA, NA, NA,
- NA),
- PINGROUP(45, NORTH, qup6, NA, reserved45, NA, NA, NA, NA, NA, NA),
- PINGROUP(46, NORTH, qup6, NA, reserved46, NA, NA, NA, NA, NA, NA),
- PINGROUP(47, NORTH, qup6, reserved47, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(48, NORTH, qup6, reserved48, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(49, NORTH, qup12, reserved49, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(50, NORTH, qup12, reserved50, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(51, NORTH, qup12, qdss_cti, reserved51, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(52, NORTH, qup12, phase_flag16, qdss_cti, reserved52, NA, NA,
- NA, NA, NA),
- PINGROUP(53, NORTH, qup10, phase_flag11, reserved53, NA, NA, NA, NA,
- NA, NA),
- PINGROUP(54, NORTH, qup10, NA, phase_flag12, reserved54, NA, NA, NA,
- NA, NA),
- PINGROUP(55, NORTH, qup10, phase_flag13, reserved55, NA, NA, NA, NA,
- NA, NA),
- PINGROUP(56, NORTH, qup10, phase_flag17, reserved56, NA, NA, NA, NA,
- NA, NA),
- PINGROUP(57, NORTH, qua_mi2s, gcc_gp1, phase_flag18, reserved57, NA,
- NA, NA, NA, NA),
- PINGROUP(58, NORTH, qua_mi2s, gcc_gp2, phase_flag19, reserved58, NA,
- NA, NA, NA, NA),
- PINGROUP(59, NORTH, qua_mi2s, gcc_gp3, phase_flag20, reserved59, NA,
- NA, NA, NA, NA),
- PINGROUP(60, NORTH, qua_mi2s, cri_trng0, phase_flag21, reserved60, NA,
- NA, NA, NA, NA),
- PINGROUP(61, NORTH, qua_mi2s, cri_trng1, phase_flag22, reserved61, NA,
- NA, NA, NA, NA),
- PINGROUP(62, NORTH, qua_mi2s, cri_trng, phase_flag23, qdss_cti,
- reserved62, NA, NA, NA, NA),
- PINGROUP(63, NORTH, qua_mi2s, NA, phase_flag24, qdss_cti, reserved63,
- NA, NA, NA, NA),
- PINGROUP(64, NORTH, pri_mi2s, sp_cmu, phase_flag25, reserved64, NA, NA,
- NA, NA, NA),
- PINGROUP(65, NORTH, pri_mi2s, qup8, reserved65, NA, NA, NA, NA, NA, NA),
- PINGROUP(66, NORTH, pri_mi2s_ws, qup8, reserved66, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(67, NORTH, pri_mi2s, qup8, reserved67, NA, NA, NA, NA, NA, NA),
- PINGROUP(68, NORTH, pri_mi2s, qup8, reserved68, NA, NA, NA, NA, NA, NA),
- PINGROUP(69, NORTH, spkr_i2s, audio_ref, reserved69, NA, NA, NA, NA,
- NA, NA),
- PINGROUP(70, NORTH, lpass_slimbus, spkr_i2s, reserved70, NA, NA, NA,
- NA, NA, NA),
- PINGROUP(71, NORTH, lpass_slimbus, spkr_i2s, tsense_pwm1, tsense_pwm2,
- reserved71, NA, NA, NA, NA),
- PINGROUP(72, NORTH, lpass_slimbus, spkr_i2s, reserved72, NA, NA, NA,
- NA, NA, NA),
- PINGROUP(73, NORTH, btfm_slimbus, atest_usb2, reserved73, NA, NA, NA,
- NA, NA, NA),
- PINGROUP(74, NORTH, btfm_slimbus, ter_mi2s, phase_flag7, atest_usb23,
- reserved74, NA, NA, NA, NA),
- PINGROUP(75, NORTH, ter_mi2s, phase_flag8, qdss_gpio8, atest_usb22,
- reserved75, NA, NA, NA, NA),
- PINGROUP(76, NORTH, ter_mi2s, phase_flag9, qdss_gpio9, atest_usb21,
- reserved76, NA, NA, NA, NA),
- PINGROUP(77, NORTH, ter_mi2s, phase_flag4, qdss_gpio10, atest_usb20,
- reserved77, NA, NA, NA, NA),
- PINGROUP(78, NORTH, ter_mi2s, gcc_gp1, reserved78, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(79, NORTH, sec_mi2s, NA, NA, qdss_gpio11, reserved79, NA, NA,
- NA, NA),
- PINGROUP(80, NORTH, sec_mi2s, NA, qdss_gpio12, reserved80, NA, NA, NA,
- NA, NA),
- PINGROUP(81, NORTH, sec_mi2s, qup15, NA, reserved81, NA, NA, NA, NA,
- NA),
- PINGROUP(82, NORTH, sec_mi2s, qup15, NA, reserved82, NA, NA, NA, NA,
- NA),
- PINGROUP(83, NORTH, sec_mi2s, qup15, NA, reserved83, NA, NA, NA, NA,
- NA),
- PINGROUP(84, NORTH, qup15, NA, reserved84, NA, NA, NA, NA, NA, NA),
- PINGROUP(85, SOUTH, qup5, NA, reserved85, NA, NA, NA, NA, NA, NA),
- PINGROUP(86, SOUTH, qup5, NA, NA, reserved86, NA, NA, NA, NA, NA),
- PINGROUP(87, SOUTH, qup5, NA, reserved87, NA, NA, NA, NA, NA, NA),
- PINGROUP(88, SOUTH, qup5, NA, reserved88, NA, NA, NA, NA, NA, NA),
- PINGROUP(89, SOUTH, tsif1_clk, qup4, tgu_ch3, phase_flag10, reserved89,
- NA, NA, NA, NA),
- PINGROUP(90, SOUTH, tsif1_en, mdp_vsync0, qup4, mdp_vsync1, mdp_vsync2,
- mdp_vsync3, tgu_ch0, phase_flag0, qdss_cti),
- PINGROUP(91, SOUTH, tsif1_data, sdc4_cmd, qup4, tgu_ch1, NA, qdss_cti,
- reserved91, NA, NA),
- PINGROUP(92, SOUTH, tsif2_error, sdc43, qup4, vfr_1, tgu_ch2, NA,
- reserved92, NA, NA),
- PINGROUP(93, SOUTH, tsif2_clk, sdc4_clk, qup7, NA, qdss_gpio13,
- reserved93, NA, NA, NA),
- PINGROUP(94, SOUTH, tsif2_en, sdc42, qup7, NA, reserved94, NA, NA, NA,
- NA),
- PINGROUP(95, SOUTH, tsif2_data, sdc41, qup7, NA, NA, reserved95, NA,
- NA, NA),
- PINGROUP(96, SOUTH, tsif2_sync, sdc40, qup7, phase_flag3, reserved96,
- NA, NA, NA, NA),
- PINGROUP(97, NORTH, NA, NA, mdp_vsync, ldo_en, reserved97, NA, NA, NA,
- NA),
- PINGROUP(98, NORTH, NA, mdp_vsync, ldo_update, reserved98, NA, NA, NA,
- NA, NA),
- PINGROUP(99, NORTH, phase_flag14, reserved99, NA, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(100, NORTH, phase_flag15, reserved100, NA, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(101, NORTH, NA, reserved101, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(102, NORTH, pci_e1, prng_rosc, reserved102, NA, NA, NA, NA,
- NA, NA),
- PINGROUP(103, NORTH, pci_e1, phase_flag5, reserved103, NA, NA, NA, NA,
- NA, NA),
- PINGROUP(104, NORTH, NA, reserved104, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(105, NORTH, uim2_data, qup13, qup_l4, NA, reserved105, NA, NA,
- NA, NA),
- PINGROUP(106, NORTH, uim2_clk, qup13, qup_l5, NA, reserved106, NA, NA,
- NA, NA),
- PINGROUP(107, NORTH, uim2_reset, qup13, qup_l6, reserved107, NA, NA,
- NA, NA, NA),
- PINGROUP(108, NORTH, uim2_present, qup13, reserved108, NA, NA, NA, NA,
- NA, NA),
- PINGROUP(109, NORTH, uim1_data, reserved109, NA, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(110, NORTH, uim1_clk, reserved110, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(111, NORTH, uim1_reset, reserved111, NA, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(112, NORTH, uim1_present, reserved112, NA, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(113, NORTH, uim_batt, edp_hot, reserved113, NA, NA, NA, NA,
- NA, NA),
- PINGROUP(114, NORTH, NA, nav_pps, nav_pps, NA, NA, reserved114, NA, NA,
- NA),
- PINGROUP(115, NORTH, NA, nav_pps, nav_pps, NA, NA, reserved115, NA, NA,
- NA),
- PINGROUP(116, NORTH, NA, reserved116, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(117, NORTH, NA, qdss_gpio0, atest_char, reserved117, NA, NA,
- NA, NA, NA),
- PINGROUP(118, NORTH, adsp_ext, NA, qdss_gpio1, atest_char3,
- reserved118, NA, NA, NA, NA),
- PINGROUP(119, NORTH, NA, qdss_gpio2, atest_char2, reserved119, NA, NA,
- NA, NA, NA),
- PINGROUP(120, NORTH, NA, qdss_gpio3, atest_char1, reserved120, NA, NA,
- NA, NA, NA),
- PINGROUP(121, NORTH, NA, qdss_gpio4, atest_char0, reserved121, NA, NA,
- NA, NA, NA),
- PINGROUP(122, NORTH, NA, qdss_gpio5, reserved122, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(123, NORTH, qup_l4, NA, qdss_gpio, reserved123, NA, NA, NA,
- NA, NA),
- PINGROUP(124, NORTH, qup_l5, NA, qdss_gpio, reserved124, NA, NA, NA,
- NA, NA),
- PINGROUP(125, NORTH, qup_l6, NA, reserved125, NA, NA, NA, NA, NA, NA),
- PINGROUP(126, NORTH, NA, reserved126, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(127, NORTH, NA, reserved127, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(128, NORTH, nav_pps, nav_pps, NA, NA, reserved128, NA, NA, NA,
- NA),
- PINGROUP(129, NORTH, nav_pps, nav_pps, NA, NA, reserved129, NA, NA, NA,
- NA),
- PINGROUP(130, NORTH, qlink_request, NA, reserved130, NA, NA, NA, NA,
- NA, NA),
- PINGROUP(131, NORTH, qlink_enable, NA, reserved131, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(132, NORTH, NA, NA, reserved132, NA, NA, NA, NA, NA, NA),
- PINGROUP(133, NORTH, NA, reserved133, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(134, NORTH, NA, reserved134, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(135, NORTH, NA, pa_indicator, NA, reserved135, NA, NA, NA, NA,
- NA),
- PINGROUP(136, NORTH, NA, reserved136, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(137, NORTH, NA, NA, phase_flag26, reserved137, NA, NA, NA, NA,
- NA),
- PINGROUP(138, NORTH, NA, NA, phase_flag27, reserved138, NA, NA, NA, NA,
- NA),
- PINGROUP(139, NORTH, NA, phase_flag28, reserved139, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(140, NORTH, NA, NA, phase_flag6, reserved140, NA, NA, NA, NA,
- NA),
- PINGROUP(141, NORTH, NA, phase_flag29, reserved141, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(142, NORTH, NA, phase_flag30, reserved142, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(143, NORTH, NA, nav_pps, nav_pps, NA, phase_flag31,
- reserved143, NA, NA, NA),
- PINGROUP(144, NORTH, mss_lte, reserved144, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(145, NORTH, mss_lte, NA, reserved145, NA, NA, NA, NA, NA, NA),
- PINGROUP(146, NORTH, NA, NA, reserved146, NA, NA, NA, NA, NA, NA),
- PINGROUP(147, NORTH, NA, NA, reserved147, NA, NA, NA, NA, NA, NA),
- PINGROUP(148, NORTH, NA, reserved148, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(149, NORTH, NA, reserved149, NA, NA, NA, NA, NA, NA, NA),
- SDC_QDSD_PINGROUP(sdc2_clk, 0x99a000, 14, 6),
- SDC_QDSD_PINGROUP(sdc2_cmd, 0x99a000, 11, 3),
- SDC_QDSD_PINGROUP(sdc2_data, 0x99a000, 9, 0),
- UFS_RESET(ufs_reset, 0x99f000),
+ [0] = PINGROUP(0, qup0, NA, NA, NA, NA, NA, NA, NA, NA),
+ [1] = PINGROUP(1, qup0, NA, NA, NA, NA, NA, NA, NA, NA),
+ [2] = PINGROUP(2, qup0, NA, NA, NA, NA, NA, NA, NA, NA),
+ [3] = PINGROUP(3, qup0, NA, NA, NA, NA, NA, NA, NA, NA),
+ [4] = PINGROUP(4, qup9, qdss_cti, NA, NA, NA, NA, NA, NA, NA),
+ [5] = PINGROUP(5, qup9, qdss_cti, NA, NA, NA, NA, NA, NA, NA),
+ [6] = PINGROUP(6, qup9, NA, ddr_pxi0, NA, NA, NA, NA, NA, NA),
+ [7] = PINGROUP(7, qup9, ddr_bist, NA, atest_tsens2,
+ vsense_trigger, atest_usb1, ddr_pxi0, NA, NA),
+ [8] = PINGROUP(8, qup_l4, NA, ddr_bist, NA, NA, wlan1_adc1,
+ atest_usb13, ddr_pxi1, NA),
+ [9] = PINGROUP(9, qup_l5, ddr_bist, NA, wlan1_adc0, atest_usb12,
+ ddr_pxi1, NA, NA, NA),
+ [10] = PINGROUP(10, mdp_vsync, qup_l6, ddr_bist, wlan2_adc1,
+ atest_usb11, ddr_pxi2, NA, NA, NA),
+ [11] = PINGROUP(11, mdp_vsync, edp_lcd, dbg_out, wlan2_adc0,
+ atest_usb10, ddr_pxi2, NA, NA, NA),
+ [12] = PINGROUP(12, mdp_vsync, m_voc, tsif1_sync, ddr_pxi3, NA,
+ NA, NA, NA, NA),
+ [13] = PINGROUP(13, cam_mclk, pll_bypassnl, qdss_gpio0,
+ ddr_pxi3, NA, NA, NA, NA, NA),
+ [14] = PINGROUP(14, cam_mclk, pll_reset, qdss_gpio1, NA, NA, NA,
+ NA, NA, NA),
+ [15] = PINGROUP(15, cam_mclk, qdss_gpio2, NA, NA, NA, NA, NA,
+ NA, NA),
+ [16] = PINGROUP(16, cam_mclk, qdss_gpio3, NA, NA, NA, NA, NA,
+ NA, NA),
+ [17] = PINGROUP(17, cci_i2c, qup1, qdss_gpio4, NA, NA, NA, NA,
+ NA, NA),
+ [18] = PINGROUP(18, cci_i2c, qup1, NA, qdss_gpio5, NA, NA, NA,
+ NA, NA),
+ [19] = PINGROUP(19, cci_i2c, qup1, NA, qdss_gpio6, NA, NA, NA,
+ NA, NA),
+ [20] = PINGROUP(20, cci_i2c, qup1, NA, qdss_gpio7, NA, NA, NA,
+ NA, NA),
+ [21] = PINGROUP(21, cci_timer0, gcc_gp2, qdss_gpio8, NA, NA, NA,
+ NA, NA, NA),
+ [22] = PINGROUP(22, cci_timer1, gcc_gp3, qdss_gpio, NA, NA, NA,
+ NA, NA, NA),
+ [23] = PINGROUP(23, cci_timer2, qdss_gpio9, NA, NA, NA, NA, NA,
+ NA, NA),
+ [24] = PINGROUP(24, cci_timer3, cci_async, qdss_gpio10, NA, NA,
+ NA, NA, NA, NA),
+ [25] = PINGROUP(25, cci_timer4, cci_async, qdss_gpio11, NA, NA,
+ NA, NA, NA, NA),
+ [26] = PINGROUP(26, cci_async, qdss_gpio12, NA, NA, NA, NA, NA,
+ NA, NA),
+ [27] = PINGROUP(27, qup2, qdss_gpio13, NA, NA, NA, NA, NA, NA,
+ NA),
+ [28] = PINGROUP(28, qup2, qdss_gpio14, NA, NA, NA, NA, NA, NA,
+ NA),
+ [29] = PINGROUP(29, qup2, NA, phase_flag1, qdss_gpio15, NA, NA,
+ NA, NA, NA),
+ [30] = PINGROUP(30, qup2, phase_flag2, qdss_gpio, NA, NA, NA, NA,
+ NA, NA),
+ [31] = PINGROUP(31, qup11, qup14, NA, NA, NA, NA, NA, NA, NA),
+ [32] = PINGROUP(32, qup11, qup14, NA, NA, NA, NA, NA, NA, NA),
+ [33] = PINGROUP(33, qup11, qup14, NA, NA, NA, NA, NA, NA, NA),
+ [34] = PINGROUP(34, qup11, qup14, NA, NA, NA, NA, NA, NA, NA),
+ [35] = PINGROUP(35, pci_e0, qup_l4, jitter_bist, NA, NA, NA, NA,
+ NA, NA),
+ [36] = PINGROUP(36, pci_e0, qup_l5, pll_bist, NA, atest_tsens,
+ NA, NA, NA, NA),
+ [37] = PINGROUP(37, qup_l6, agera_pll, NA, NA, NA, NA, NA, NA,
+ NA),
+ [38] = PINGROUP(38, usb_phy, NA, NA, NA, NA, NA, NA, NA, NA),
+ [39] = PINGROUP(39, lpass_slimbus, NA, NA, NA, NA, NA, NA, NA,
+ NA),
+ [40] = PINGROUP(40, sd_write, tsif1_error, NA, NA, NA, NA, NA,
+ NA, NA),
+ [41] = PINGROUP(41, qup3, NA, qdss_gpio6, NA, NA, NA, NA, NA, NA),
+ [42] = PINGROUP(42, qup3, NA, qdss_gpio7, NA, NA, NA, NA, NA, NA),
+ [43] = PINGROUP(43, qup3, NA, qdss_gpio14, NA, NA, NA, NA, NA,
+ NA),
+ [44] = PINGROUP(44, qup3, NA, qdss_gpio15, NA, NA, NA, NA, NA,
+ NA),
+ [45] = PINGROUP(45, qup6, NA, NA, NA, NA, NA, NA, NA, NA),
+ [46] = PINGROUP(46, qup6, NA, NA, NA, NA, NA, NA, NA, NA),
+ [47] = PINGROUP(47, qup6, NA, NA, NA, NA, NA, NA, NA, NA),
+ [48] = PINGROUP(48, qup6, NA, NA, NA, NA, NA, NA, NA, NA),
+ [49] = PINGROUP(49, qup12, NA, NA, NA, NA, NA, NA, NA, NA),
+ [50] = PINGROUP(50, qup12, NA, NA, NA, NA, NA, NA, NA, NA),
+ [51] = PINGROUP(51, qup12, qdss_cti, NA, NA, NA, NA, NA, NA, NA),
+ [52] = PINGROUP(52, qup12, phase_flag16, qdss_cti, NA, NA, NA,
+ NA, NA, NA),
+ [53] = PINGROUP(53, qup10, phase_flag11, NA, NA, NA, NA, NA, NA,
+ NA),
+ [54] = PINGROUP(54, qup10, NA, phase_flag12, NA, NA, NA, NA, NA,
+ NA),
+ [55] = PINGROUP(55, qup10, phase_flag13, NA, NA, NA, NA, NA, NA,
+ NA),
+ [56] = PINGROUP(56, qup10, phase_flag17, NA, NA, NA, NA, NA, NA,
+ NA),
+ [57] = PINGROUP(57, qua_mi2s, gcc_gp1, phase_flag18, NA, NA, NA,
+ NA, NA, NA),
+ [58] = PINGROUP(58, qua_mi2s, gcc_gp2, phase_flag19, NA, NA, NA,
+ NA, NA, NA),
+ [59] = PINGROUP(59, qua_mi2s, gcc_gp3, phase_flag20, NA, NA, NA,
+ NA, NA, NA),
+ [60] = PINGROUP(60, qua_mi2s, cri_trng0, phase_flag21, NA, NA,
+ NA, NA, NA, NA),
+ [61] = PINGROUP(61, qua_mi2s, cri_trng1, phase_flag22, NA, NA,
+ NA, NA, NA, NA),
+ [62] = PINGROUP(62, qua_mi2s, cri_trng, phase_flag23, qdss_cti,
+ NA, NA, NA, NA, NA),
+ [63] = PINGROUP(63, qua_mi2s, NA, phase_flag24, qdss_cti, NA,
+ NA, NA, NA, NA),
+ [64] = PINGROUP(64, pri_mi2s, sp_cmu, phase_flag25, NA, NA, NA,
+ NA, NA, NA),
+ [65] = PINGROUP(65, pri_mi2s, qup8, NA, NA, NA, NA, NA, NA, NA),
+ [66] = PINGROUP(66, pri_mi2s_ws, qup8, NA, NA, NA, NA, NA, NA,
+ NA),
+ [67] = PINGROUP(67, pri_mi2s, qup8, NA, NA, NA, NA, NA, NA, NA),
+ [68] = PINGROUP(68, pri_mi2s, qup8, NA, NA, NA, NA, NA, NA, NA),
+ [69] = PINGROUP(69, spkr_i2s, audio_ref, NA, NA, NA, NA, NA, NA,
+ NA),
+ [70] = PINGROUP(70, lpass_slimbus, spkr_i2s, NA, NA, NA, NA, NA,
+ NA, NA),
+ [71] = PINGROUP(71, lpass_slimbus, spkr_i2s, tsense_pwm1,
+ tsense_pwm2, NA, NA, NA, NA, NA),
+ [72] = PINGROUP(72, lpass_slimbus, spkr_i2s, NA, NA, NA, NA, NA,
+ NA, NA),
+ [73] = PINGROUP(73, btfm_slimbus, atest_usb2, NA, NA, NA, NA, NA,
+ NA, NA),
+ [74] = PINGROUP(74, btfm_slimbus, ter_mi2s, phase_flag7,
+ atest_usb23, NA, NA, NA, NA, NA),
+ [75] = PINGROUP(75, ter_mi2s, phase_flag8, qdss_gpio8,
+ atest_usb22, NA, NA, NA, NA, NA),
+ [76] = PINGROUP(76, ter_mi2s, phase_flag9, qdss_gpio9,
+ atest_usb21, NA, NA, NA, NA, NA),
+ [77] = PINGROUP(77, ter_mi2s, phase_flag4, qdss_gpio10,
+ atest_usb20, NA, NA, NA, NA, NA),
+ [78] = PINGROUP(78, ter_mi2s, gcc_gp1, NA, NA, NA, NA, NA, NA,
+ NA),
+ [79] = PINGROUP(79, sec_mi2s, NA, NA, qdss_gpio11, NA, NA, NA,
+ NA, NA),
+ [80] = PINGROUP(80, sec_mi2s, NA, qdss_gpio12, NA, NA, NA, NA,
+ NA, NA),
+ [81] = PINGROUP(81, sec_mi2s, qup15, NA, NA, NA, NA, NA, NA, NA),
+ [82] = PINGROUP(82, sec_mi2s, qup15, NA, NA, NA, NA, NA, NA, NA),
+ [83] = PINGROUP(83, sec_mi2s, qup15, NA, NA, NA, NA, NA, NA, NA),
+ [84] = PINGROUP(84, qup15, NA, NA, NA, NA, NA, NA, NA, NA),
+ [85] = PINGROUP(85, qup5, NA, NA, NA, NA, NA, NA, NA, NA),
+ [86] = PINGROUP(86, qup5, NA, NA, NA, NA, NA, NA, NA, NA),
+ [87] = PINGROUP(87, qup5, NA, NA, NA, NA, NA, NA, NA, NA),
+ [88] = PINGROUP(88, qup5, NA, NA, NA, NA, NA, NA, NA, NA),
+ [89] = PINGROUP(89, tsif1_clk, qup4, tgu_ch3, phase_flag10, NA,
+ NA, NA, NA, NA),
+ [90] = PINGROUP(90, tsif1_en, mdp_vsync0, qup4, mdp_vsync1,
+ mdp_vsync2, mdp_vsync3, tgu_ch0, phase_flag0, qdss_cti),
+ [91] = PINGROUP(91, tsif1_data, sdc4_cmd, qup4, tgu_ch1, NA,
+ qdss_cti, NA, NA, NA),
+ [92] = PINGROUP(92, tsif2_error, sdc43, qup4, vfr_1, tgu_ch2,
+ NA, NA, NA, NA),
+ [93] = PINGROUP(93, tsif2_clk, sdc4_clk, qup7, NA, qdss_gpio13,
+ NA, NA, NA, NA),
+ [94] = PINGROUP(94, tsif2_en, sdc42, qup7, NA, NA, NA, NA, NA,
+ NA),
+ [95] = PINGROUP(95, tsif2_data, sdc41, qup7, NA, NA, NA, NA, NA,
+ NA),
+ [96] = PINGROUP(96, tsif2_sync, sdc40, qup7, phase_flag3, NA,
+ NA, NA, NA, NA),
+ [97] = PINGROUP(97, NA, NA, mdp_vsync, ldo_en, NA, NA, NA, NA,
+ NA),
+ [98] = PINGROUP(98, NA, mdp_vsync, ldo_update, NA, NA, NA, NA,
+ NA, NA),
+ [99] = PINGROUP(99, phase_flag14, NA, NA, NA, NA, NA, NA, NA,
+ NA),
+ [100] = PINGROUP(100, phase_flag15, NA, NA, NA, NA, NA, NA, NA,
+ NA),
+ [101] = PINGROUP(101, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [102] = PINGROUP(102, pci_e1, prng_rosc, NA, NA, NA, NA, NA, NA,
+ NA),
+ [103] = PINGROUP(103, pci_e1, phase_flag5, NA, NA, NA, NA, NA,
+ NA, NA),
+ [104] = PINGROUP(104, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [105] = PINGROUP(105, uim2_data, qup13, qup_l4, NA, NA, NA, NA,
+ NA, NA),
+ [106] = PINGROUP(106, uim2_clk, qup13, qup_l5, NA, NA, NA, NA,
+ NA, NA),
+ [107] = PINGROUP(107, uim2_reset, qup13, qup_l6, NA, NA, NA, NA,
+ NA, NA),
+ [108] = PINGROUP(108, uim2_present, qup13, NA, NA, NA, NA, NA,
+ NA, NA),
+ [109] = PINGROUP(109, uim1_data, NA, NA, NA, NA, NA, NA, NA, NA),
+ [110] = PINGROUP(110, uim1_clk, NA, NA, NA, NA, NA, NA, NA, NA),
+ [111] = PINGROUP(111, uim1_reset, NA, NA, NA, NA, NA, NA, NA,
+ NA),
+ [112] = PINGROUP(112, uim1_present, NA, NA, NA, NA, NA, NA, NA,
+ NA),
+ [113] = PINGROUP(113, uim_batt, edp_hot, NA, NA, NA, NA, NA, NA,
+ NA),
+ [114] = PINGROUP(114, NA, nav_pps, nav_pps, NA, NA, NA, NA, NA,
+ NA),
+ [115] = PINGROUP(115, NA, nav_pps, nav_pps, NA, NA, NA, NA, NA,
+ NA),
+ [116] = PINGROUP(116, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [117] = PINGROUP(117, NA, qdss_gpio0, atest_char, NA, NA, NA,
+ NA, NA, NA),
+ [118] = PINGROUP(118, adsp_ext, NA, qdss_gpio1, atest_char3, NA,
+ NA, NA, NA, NA),
+ [119] = PINGROUP(119, NA, qdss_gpio2, atest_char2, NA, NA, NA,
+ NA, NA, NA),
+ [120] = PINGROUP(120, NA, qdss_gpio3, atest_char1, NA, NA, NA,
+ NA, NA, NA),
+ [121] = PINGROUP(121, NA, qdss_gpio4, atest_char0, NA, NA, NA,
+ NA, NA, NA),
+ [122] = PINGROUP(122, NA, qdss_gpio5, NA, NA, NA, NA, NA, NA, NA),
+ [123] = PINGROUP(123, qup_l4, NA, qdss_gpio, NA, NA, NA, NA, NA,
+ NA),
+ [124] = PINGROUP(124, qup_l5, NA, qdss_gpio, NA, NA, NA, NA, NA,
+ NA),
+ [125] = PINGROUP(125, qup_l6, NA, NA, NA, NA, NA, NA, NA, NA),
+ [126] = PINGROUP(126, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [127] = PINGROUP(127, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [128] = PINGROUP(128, nav_pps, nav_pps, NA, NA, NA, NA, NA, NA,
+ NA),
+ [129] = PINGROUP(129, nav_pps, nav_pps, NA, NA, NA, NA, NA, NA,
+ NA),
+ [130] = PINGROUP(130, qlink_request, NA, NA, NA, NA, NA, NA, NA,
+ NA),
+ [131] = PINGROUP(131, qlink_enable, NA, NA, NA, NA, NA, NA, NA,
+ NA),
+ [132] = PINGROUP(132, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [133] = PINGROUP(133, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [134] = PINGROUP(134, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [135] = PINGROUP(135, NA, pa_indicator, NA, NA, NA, NA, NA, NA,
+ NA),
+ [136] = PINGROUP(136, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [137] = PINGROUP(137, NA, NA, phase_flag26, NA, NA, NA, NA, NA,
+ NA),
+ [138] = PINGROUP(138, NA, NA, phase_flag27, NA, NA, NA, NA, NA,
+ NA),
+ [139] = PINGROUP(139, NA, phase_flag28, NA, NA, NA, NA, NA, NA,
+ NA),
+ [140] = PINGROUP(140, NA, NA, phase_flag6, NA, NA, NA, NA, NA,
+ NA),
+ [141] = PINGROUP(141, NA, phase_flag29, NA, NA, NA, NA, NA, NA,
+ NA),
+ [142] = PINGROUP(142, NA, phase_flag30, NA, NA, NA, NA, NA, NA,
+ NA),
+ [143] = PINGROUP(143, NA, nav_pps, nav_pps, NA, phase_flag31,
+ NA, NA, NA, NA),
+ [144] = PINGROUP(144, mss_lte, NA, NA, NA, NA, NA, NA, NA, NA),
+ [145] = PINGROUP(145, mss_lte, NA, NA, NA, NA, NA, NA, NA, NA),
+ [146] = PINGROUP(146, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [147] = PINGROUP(147, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [148] = PINGROUP(148, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [149] = PINGROUP(149, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [150] = SDC_QDSD_PINGROUP(sdc2_clk, 0x99a000, 14, 6),
+ [151] = SDC_QDSD_PINGROUP(sdc2_cmd, 0x99a000, 11, 3),
+ [152] = SDC_QDSD_PINGROUP(sdc2_data, 0x99a000, 9, 0),
+ [153] = UFS_RESET(ufs_reset, 0x99f000),
};
static const struct msm_dir_conn sdm845_dir_conn[] = {
@@ -2465,6 +1714,10 @@
.ngpios = 150,
.dir_conn = sdm845_dir_conn,
.n_dir_conns = ARRAY_SIZE(sdm845_dir_conn),
+ .tile_offsets = sdm845_tile_offsets,
+ .n_tile_offsets = ARRAY_SIZE(sdm845_tile_offsets),
+ .pin_base = sdm845_pin_base,
+ .reg_size = REG_SIZE,
};
static int sdm845_pinctrl_probe(struct platform_device *pdev)
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c
index c8663c9..d4e39d7 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c
@@ -649,8 +649,7 @@
return 0;
ipa_insert_failed:
- if (offset)
- list_move(&offset->link,
+ list_move(&offset->link,
&htbl->head_free_offset_list[offset->bin]);
entry->offset_entry = NULL;
list_del(&entry->link);
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
index 0a3c0e5..50930d3 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
@@ -1363,6 +1363,10 @@
mutex_lock(&ipa_ctx->lock);
entry = __ipa_find_rt_tbl(lookup->ip, lookup->name);
if (entry && entry->cookie == IPA_RT_TBL_COOKIE) {
+ if (entry->ref_cnt == U32_MAX) {
+ IPAERR("fail: ref count crossed limit\n");
+ goto ret;
+ }
entry->ref_cnt++;
lookup->hdl = entry->id;
@@ -1372,6 +1376,8 @@
result = 0;
}
+
+ret:
mutex_unlock(&ipa_ctx->lock);
return result;
@@ -1389,7 +1395,7 @@
{
struct ipa_rt_tbl *entry;
enum ipa_ip_type ip = IPA_IP_MAX;
- int result;
+ int result = 0;
mutex_lock(&ipa_ctx->lock);
entry = ipa_id_find(rt_tbl_hdl);
diff --git a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c
index 0bdfea9..9c75202 100644
--- a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c
@@ -1877,7 +1877,9 @@
if (ret < 0)
IPAWANERR("Error deleting resource %d, ret=%d\n",
IPA_RM_RESOURCE_Q6_PROD, ret);
- destroy_workqueue(ipa_rm_q6_workqueue);
+
+ if (ipa_rm_q6_workqueue)
+ destroy_workqueue(ipa_rm_q6_workqueue);
}
static void wake_tx_queue(struct work_struct *work)
@@ -2186,7 +2188,10 @@
IPAWANERR("Error deleting resource %d, ret=%d\n",
IPA_RM_RESOURCE_WWAN_0_PROD, ret);
create_rsrc_err:
- q6_deinitialize_rm();
+
+ if (!atomic_read(&is_ssr))
+ q6_deinitialize_rm();
+
q6_init_err:
free_netdev(ipa_netdevs[0]);
ipa_netdevs[0] = NULL;
diff --git a/drivers/platform/msm/ipa/ipa_v3/Makefile b/drivers/platform/msm/ipa/ipa_v3/Makefile
index a4faaea..e3f8d45 100644
--- a/drivers/platform/msm/ipa/ipa_v3/Makefile
+++ b/drivers/platform/msm/ipa/ipa_v3/Makefile
@@ -3,6 +3,7 @@
obj-$(CONFIG_IPA3) += ipat.o
ipat-y := ipa.o ipa_debugfs.o ipa_hdr.o ipa_flt.o ipa_rt.o ipa_dp.o ipa_client.o \
ipa_utils.o ipa_nat.o ipa_intf.o teth_bridge.o ipa_interrupts.o \
- ipa_uc.o ipa_uc_wdi.o ipa_dma.o ipa_uc_mhi.o ipa_mhi.o ipa_uc_ntn.o
+ ipa_uc.o ipa_uc_wdi.o ipa_dma.o ipa_uc_mhi.o ipa_mhi.o ipa_uc_ntn.o \
+ ipa_hw_stats.o
obj-$(CONFIG_RMNET_IPA3) += rmnet_ipa.o ipa_qmi_service_v01.o ipa_qmi_service.o rmnet_ipa_fd_ioctl.o
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index 9ebe111..4d4e993 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -3947,14 +3947,17 @@
int i;
struct ipa3_flt_tbl *flt_tbl;
+ idr_destroy(&ipa3_ctx->flt_rule_ids[IPA_IP_v4]);
+ idr_destroy(&ipa3_ctx->flt_rule_ids[IPA_IP_v6]);
+
for (i = 0; i < ipa3_ctx->ipa_num_pipes; i++) {
if (!ipa_is_ep_support_flt(i))
continue;
flt_tbl = &ipa3_ctx->flt_tbl[i][IPA_IP_v4];
- idr_destroy(&flt_tbl->rule_ids);
+ flt_tbl->rule_ids = NULL;
flt_tbl = &ipa3_ctx->flt_tbl[i][IPA_IP_v6];
- idr_destroy(&flt_tbl->rule_ids);
+ flt_tbl->rule_ids = NULL;
}
}
@@ -4129,6 +4132,7 @@
struct ipa3_uc_hdlrs uc_hdlrs = { 0 };
struct ipa3_flt_tbl *flt_tbl;
int i;
+ struct idr *idr;
if (ipa3_ctx == NULL) {
IPADBG("IPA driver haven't initialized\n");
@@ -4152,6 +4156,11 @@
/* Assign resource limitation to each group */
ipa3_set_resorce_groups_min_max_limits();
+ idr = &(ipa3_ctx->flt_rule_ids[IPA_IP_v4]);
+ idr_init(idr);
+ idr = &(ipa3_ctx->flt_rule_ids[IPA_IP_v6]);
+ idr_init(idr);
+
for (i = 0; i < ipa3_ctx->ipa_num_pipes; i++) {
if (!ipa_is_ep_support_flt(i))
continue;
@@ -4162,7 +4171,7 @@
!ipa3_ctx->ip4_flt_tbl_hash_lcl;
flt_tbl->in_sys[IPA_RULE_NON_HASHABLE] =
!ipa3_ctx->ip4_flt_tbl_nhash_lcl;
- idr_init(&flt_tbl->rule_ids);
+ flt_tbl->rule_ids = &ipa3_ctx->flt_rule_ids[IPA_IP_v4];
flt_tbl = &ipa3_ctx->flt_tbl[i][IPA_IP_v6];
INIT_LIST_HEAD(&flt_tbl->head_flt_rule_list);
@@ -4170,7 +4179,7 @@
!ipa3_ctx->ip6_flt_tbl_hash_lcl;
flt_tbl->in_sys[IPA_RULE_NON_HASHABLE] =
!ipa3_ctx->ip6_flt_tbl_nhash_lcl;
- idr_init(&flt_tbl->rule_ids);
+ flt_tbl->rule_ids = &ipa3_ctx->flt_rule_ids[IPA_IP_v6];
}
if (!ipa3_ctx->apply_rg10_wa) {
@@ -4255,6 +4264,12 @@
else
IPADBG(":ntn init ok\n");
+ result = ipa_hw_stats_init();
+ if (result)
+ IPAERR("fail to init stats %d\n", result);
+ else
+ IPADBG(":stats init ok\n");
+
ipa3_register_panic_hdlr();
ipa3_ctx->q6_proxy_clk_vote_valid = true;
@@ -4815,12 +4830,16 @@
hdr_proc_ctx_tbl.head_free_offset_list[i]);
}
INIT_LIST_HEAD(&ipa3_ctx->rt_tbl_set[IPA_IP_v4].head_rt_tbl_list);
+ idr_init(&ipa3_ctx->rt_tbl_set[IPA_IP_v4].rule_ids);
INIT_LIST_HEAD(&ipa3_ctx->rt_tbl_set[IPA_IP_v6].head_rt_tbl_list);
+ idr_init(&ipa3_ctx->rt_tbl_set[IPA_IP_v6].rule_ids);
rset = &ipa3_ctx->reap_rt_tbl_set[IPA_IP_v4];
INIT_LIST_HEAD(&rset->head_rt_tbl_list);
+ idr_init(&rset->rule_ids);
rset = &ipa3_ctx->reap_rt_tbl_set[IPA_IP_v6];
INIT_LIST_HEAD(&rset->head_rt_tbl_list);
+ idr_init(&rset->rule_ids);
INIT_LIST_HEAD(&ipa3_ctx->intf_list);
INIT_LIST_HEAD(&ipa3_ctx->msg_list);
@@ -4940,6 +4959,12 @@
fail_device_create:
unregister_chrdev_region(ipa3_ctx->dev_num, 1);
fail_alloc_chrdev_region:
+ rset = &ipa3_ctx->reap_rt_tbl_set[IPA_IP_v6];
+ idr_destroy(&rset->rule_ids);
+ rset = &ipa3_ctx->reap_rt_tbl_set[IPA_IP_v4];
+ idr_destroy(&rset->rule_ids);
+ idr_destroy(&ipa3_ctx->rt_tbl_set[IPA_IP_v6].rule_ids);
+ idr_destroy(&ipa3_ctx->rt_tbl_set[IPA_IP_v4].rule_ids);
ipa3_free_dma_task_for_gsi();
fail_dma_task:
idr_destroy(&ipa3_ctx->ipa_idr);
@@ -5595,6 +5620,10 @@
struct device_node *node = dev->of_node;
int res;
+ if (ipa3_ctx == NULL) {
+ IPAERR("ipa3_ctx was not initialized\n");
+ return -ENXIO;
+ }
IPADBG("node->name=%s\n", node->name);
if (strcmp("qcom,smp2pgpio_map_ipa_1_out", node->name) == 0) {
res = of_get_gpio(node, 0);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
index f172dc4..9486b0a 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
@@ -2169,6 +2169,8 @@
goto fail;
}
+ ipa_debugfs_init_stats(dent);
+
return;
fail:
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
index 827fbe2..beca549 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
@@ -806,7 +806,7 @@
if (rule->rule_id) {
id = rule->rule_id;
} else {
- id = ipa3_alloc_rule_id(&tbl->rule_ids);
+ id = ipa3_alloc_rule_id(tbl->rule_ids);
if (id < 0) {
IPAERR("failed to allocate rule id\n");
WARN_ON(1);
@@ -880,7 +880,7 @@
list_del(&entry->link);
/* if rule id was allocated from idr, remove it */
if (!(entry->rule_id & ipahal_get_rule_id_hi_bit()))
- idr_remove(&entry->tbl->rule_ids, entry->rule_id);
+ idr_remove(entry->tbl->rule_ids, entry->rule_id);
kmem_cache_free(ipa3_ctx->flt_rule_cache, entry);
error:
@@ -927,7 +927,7 @@
list_del(&entry->link);
/* if rule id was allocated from idr, remove it */
if (!(entry->rule_id & ipahal_get_rule_id_hi_bit()))
- idr_remove(&entry->tbl->rule_ids, entry->rule_id);
+ idr_remove(entry->tbl->rule_ids, entry->rule_id);
kmem_cache_free(ipa3_ctx->flt_rule_cache, entry);
error:
@@ -961,7 +961,7 @@
entry->cookie = 0;
/* if rule id was allocated from idr, remove it */
if (!(entry->rule_id & ipahal_get_rule_id_hi_bit()))
- idr_remove(&entry->tbl->rule_ids, entry->rule_id);
+ idr_remove(entry->tbl->rule_ids, entry->rule_id);
kmem_cache_free(ipa3_ctx->flt_rule_cache, entry);
@@ -1374,7 +1374,7 @@
entry->rt_tbl->ref_cnt--;
/* if rule id was allocated from idr, remove it */
if (!(entry->rule_id & ipahal_get_rule_id_hi_bit()))
- idr_remove(&entry->tbl->rule_ids,
+ idr_remove(entry->tbl->rule_ids,
entry->rule_id);
entry->cookie = 0;
id = entry->id;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c
index da7bcd0..122c541 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c
@@ -424,8 +424,7 @@
return 0;
ipa_insert_failed:
- if (offset)
- list_move(&offset->link,
+ list_move(&offset->link,
&htbl->head_free_offset_list[offset->bin]);
entry->offset_entry = NULL;
list_del(&entry->link);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_hw_stats.c b/drivers/platform/msm/ipa/ipa_v3/ipa_hw_stats.c
new file mode 100644
index 0000000..d8785ed
--- /dev/null
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_hw_stats.c
@@ -0,0 +1,1973 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include "ipa_i.h"
+#include "ipahal/ipahal.h"
+#include "ipahal/ipahal_hw_stats.h"
+
+#define IPA_CLIENT_BIT_32(client) \
+ ((ipa3_get_ep_mapping(client) >= 0 && \
+ ipa3_get_ep_mapping(client) < IPA_STATS_MAX_PIPE_BIT) ? \
+ (1 << ipa3_get_ep_mapping(client)) : 0)
+
+int ipa_hw_stats_init(void)
+{
+ if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0)
+ return 0;
+
+ /* initialize stats here */
+ ipa3_ctx->hw_stats.enabled = true;
+ return 0;
+}
+
+int ipa_init_quota_stats(u32 pipe_bitmask)
+{
+ struct ipahal_stats_init_pyld *pyld;
+ struct ipahal_imm_cmd_dma_shared_mem cmd = { 0 };
+ struct ipahal_imm_cmd_pyld *cmd_pyld;
+ struct ipahal_imm_cmd_register_write quota_base = {0};
+ struct ipahal_imm_cmd_pyld *quota_base_pyld;
+ struct ipahal_imm_cmd_register_write quota_mask = {0};
+ struct ipahal_imm_cmd_pyld *quota_mask_pyld;
+ struct ipa3_desc desc[3] = { {0} };
+ dma_addr_t dma_address;
+ int ret;
+
+ if (!ipa3_ctx->hw_stats.enabled)
+ return 0;
+
+ /* reset driver's cache */
+ memset(&ipa3_ctx->hw_stats.quota, 0, sizeof(ipa3_ctx->hw_stats.quota));
+ ipa3_ctx->hw_stats.quota.init.enabled_bitmask = pipe_bitmask;
+ IPADBG_LOW("pipe_bitmask=0x%x\n", pipe_bitmask);
+
+ pyld = ipahal_stats_generate_init_pyld(IPAHAL_HW_STATS_QUOTA,
+ &ipa3_ctx->hw_stats.quota.init, false);
+ if (!pyld) {
+ IPAERR("failed to generate pyld\n");
+ return -EPERM;
+ }
+
+ if (pyld->len > IPA_MEM_PART(stats_quota_size)) {
+ IPAERR("SRAM partition too small: %d needed %d\n",
+ IPA_MEM_PART(stats_quota_size), pyld->len);
+ ret = -EPERM;
+ goto destroy_init_pyld;
+ }
+
+ dma_address = dma_map_single(ipa3_ctx->pdev,
+ pyld->data,
+ pyld->len,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(ipa3_ctx->pdev, dma_address)) {
+ IPAERR("failed to DMA map\n");
+ ret = -EPERM;
+ goto destroy_init_pyld;
+ }
+
+ /* setting the registers and init the stats pyld are done atomically */
+ quota_mask.skip_pipeline_clear = false;
+ quota_mask.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
+ quota_mask.offset = ipahal_get_reg_n_ofst(IPA_STAT_QUOTA_MASK_n,
+ ipa3_ctx->ee);
+ quota_mask.value = pipe_bitmask;
+ quota_mask.value_mask = ~0;
+ quota_mask_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_REGISTER_WRITE,
+ "a_mask, false);
+ if (!quota_mask_pyld) {
+ IPAERR("failed to construct register_write imm cmd\n");
+ ret = -ENOMEM;
+ goto unmap;
+ }
+ desc[0].opcode = quota_mask_pyld->opcode;
+ desc[0].pyld = quota_mask_pyld->data;
+ desc[0].len = quota_mask_pyld->len;
+ desc[0].type = IPA_IMM_CMD_DESC;
+
+ quota_base.skip_pipeline_clear = false;
+ quota_base.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
+ quota_base.offset = ipahal_get_reg_n_ofst(IPA_STAT_QUOTA_BASE_n,
+ ipa3_ctx->ee);
+ quota_base.value = ipa3_ctx->smem_restricted_bytes +
+ IPA_MEM_PART(stats_quota_ofst);
+ quota_base.value_mask = ~0;
+ quota_base_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_REGISTER_WRITE,
+ "a_base, false);
+ if (!quota_base_pyld) {
+ IPAERR("failed to construct register_write imm cmd\n");
+ ret = -ENOMEM;
+ goto destroy_quota_mask;
+ }
+ desc[1].opcode = quota_base_pyld->opcode;
+ desc[1].pyld = quota_base_pyld->data;
+ desc[1].len = quota_base_pyld->len;
+ desc[1].type = IPA_IMM_CMD_DESC;
+
+ cmd.is_read = false;
+ cmd.skip_pipeline_clear = false;
+ cmd.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
+ cmd.size = pyld->len;
+ cmd.system_addr = dma_address;
+ cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
+ IPA_MEM_PART(stats_quota_ofst);
+ cmd_pyld = ipahal_construct_imm_cmd(
+ IPA_IMM_CMD_DMA_SHARED_MEM, &cmd, false);
+ if (!cmd_pyld) {
+ IPAERR("failed to construct dma_shared_mem imm cmd\n");
+ ret = -ENOMEM;
+ goto destroy_quota_base;
+ }
+ desc[2].opcode = cmd_pyld->opcode;
+ desc[2].pyld = cmd_pyld->data;
+ desc[2].len = cmd_pyld->len;
+ desc[2].type = IPA_IMM_CMD_DESC;
+
+ ret = ipa3_send_cmd(3, desc);
+ if (ret) {
+ IPAERR("failed to send immediate command (error %d)\n", ret);
+ goto destroy_imm;
+ }
+
+ ret = 0;
+
+destroy_imm:
+ ipahal_destroy_imm_cmd(cmd_pyld);
+destroy_quota_base:
+ ipahal_destroy_imm_cmd(quota_base_pyld);
+destroy_quota_mask:
+ ipahal_destroy_imm_cmd(quota_mask_pyld);
+unmap:
+ dma_unmap_single(ipa3_ctx->pdev, dma_address, pyld->len, DMA_TO_DEVICE);
+destroy_init_pyld:
+ ipahal_destroy_stats_init_pyld(pyld);
+ return ret;
+}
+
+int ipa_get_quota_stats(struct ipa_quota_stats_all *out)
+{
+ int i;
+ int ret;
+ struct ipahal_stats_get_offset_quota get_offset = { { 0 } };
+ struct ipahal_stats_offset offset = { 0 };
+ struct ipahal_imm_cmd_dma_shared_mem cmd = { 0 };
+ struct ipahal_imm_cmd_pyld *cmd_pyld;
+ struct ipa_mem_buffer mem;
+ struct ipa3_desc desc = { 0 };
+ struct ipahal_stats_quota_all *stats;
+
+ if (!ipa3_ctx->hw_stats.enabled)
+ return 0;
+
+ get_offset.init = ipa3_ctx->hw_stats.quota.init;
+ ret = ipahal_stats_get_offset(IPAHAL_HW_STATS_QUOTA, &get_offset,
+ &offset);
+ if (ret) {
+ IPAERR("failed to get offset from hal %d\n", ret);
+ return ret;
+ }
+
+ IPADBG_LOW("offset = %d size = %d\n", offset.offset, offset.size);
+
+ mem.size = offset.size;
+ mem.base = dma_alloc_coherent(ipa3_ctx->pdev,
+ mem.size,
+ &mem.phys_base,
+ GFP_KERNEL);
+ if (!mem.base) {
+ IPAERR("fail to alloc DMA memory");
+ return ret;
+ }
+
+ cmd.is_read = true;
+ cmd.clear_after_read = true;
+ cmd.skip_pipeline_clear = false;
+ cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
+ cmd.size = mem.size;
+ cmd.system_addr = mem.phys_base;
+ cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
+ IPA_MEM_PART(stats_quota_ofst) + offset.offset;
+ cmd_pyld = ipahal_construct_imm_cmd(
+ IPA_IMM_CMD_DMA_SHARED_MEM, &cmd, false);
+ if (!cmd_pyld) {
+ IPAERR("failed to construct dma_shared_mem imm cmd\n");
+ ret = -ENOMEM;
+ goto free_dma_mem;
+ }
+ desc.opcode = cmd_pyld->opcode;
+ desc.pyld = cmd_pyld->data;
+ desc.len = cmd_pyld->len;
+ desc.type = IPA_IMM_CMD_DESC;
+
+ ret = ipa3_send_cmd(1, &desc);
+ if (ret) {
+ IPAERR("failed to send immediate command (error %d)\n", ret);
+ goto destroy_imm;
+ }
+
+ stats = kzalloc(sizeof(*stats), GFP_KERNEL);
+ if (!stats) {
+ IPADBG("failed to alloc memory\n");
+ ret = -ENOMEM;
+ goto destroy_imm;
+ }
+
+ ret = ipahal_parse_stats(IPAHAL_HW_STATS_QUOTA,
+ &ipa3_ctx->hw_stats.quota.init, mem.base, stats);
+ if (ret) {
+ IPAERR("failed to parse stats (error %d)\n", ret);
+ goto free_stats;
+ }
+
+ /*
+ * update driver cache.
+ * the stats were read from hardware with clear_after_read meaning
+ * hardware stats are 0 now
+ */
+ for (i = 0; i < IPA_CLIENT_MAX; i++) {
+ int ep_idx = ipa3_get_ep_mapping(i);
+
+ if (ep_idx == -1 || ep_idx >= IPA3_MAX_NUM_PIPES)
+ continue;
+
+ if (ipa3_ctx->ep[ep_idx].client != i)
+ continue;
+
+ ipa3_ctx->hw_stats.quota.stats.client[i].num_ipv4_bytes +=
+ stats->stats[ep_idx].num_ipv4_bytes;
+ ipa3_ctx->hw_stats.quota.stats.client[i].num_ipv4_pkts +=
+ stats->stats[ep_idx].num_ipv4_pkts;
+ ipa3_ctx->hw_stats.quota.stats.client[i].num_ipv6_bytes +=
+ stats->stats[ep_idx].num_ipv6_bytes;
+ ipa3_ctx->hw_stats.quota.stats.client[i].num_ipv6_pkts +=
+ stats->stats[ep_idx].num_ipv6_pkts;
+ }
+
+ /* copy results to out parameter */
+ if (out)
+ *out = ipa3_ctx->hw_stats.quota.stats;
+ ret = 0;
+free_stats:
+ kfree(stats);
+destroy_imm:
+ ipahal_destroy_imm_cmd(cmd_pyld);
+free_dma_mem:
+ dma_free_coherent(ipa3_ctx->pdev, mem.size, mem.base, mem.phys_base);
+ return ret;
+
+}
+
+int ipa_reset_quota_stats(enum ipa_client_type client)
+{
+ int ret;
+ struct ipa_quota_stats *stats;
+
+ if (!ipa3_ctx->hw_stats.enabled)
+ return 0;
+
+ if (client >= IPA_CLIENT_MAX) {
+ IPAERR("invalid client %d\n", client);
+ return -EINVAL;
+ }
+
+ /* reading stats will reset them in hardware */
+ ret = ipa_get_quota_stats(NULL);
+ if (ret) {
+ IPAERR("ipa_get_quota_stats failed %d\n", ret);
+ return ret;
+ }
+
+ /* reset driver's cache */
+ stats = &ipa3_ctx->hw_stats.quota.stats.client[client];
+ memset(stats, 0, sizeof(*stats));
+ return 0;
+}
+
+int ipa_reset_all_quota_stats(void)
+{
+ int ret;
+ struct ipa_quota_stats_all *stats;
+
+ if (!ipa3_ctx->hw_stats.enabled)
+ return 0;
+
+ /* reading stats will reset them in hardware */
+ ret = ipa_get_quota_stats(NULL);
+ if (ret) {
+ IPAERR("ipa_get_quota_stats failed %d\n", ret);
+ return ret;
+ }
+
+ /* reset driver's cache */
+ stats = &ipa3_ctx->hw_stats.quota.stats;
+ memset(stats, 0, sizeof(*stats));
+ return 0;
+}
+
+int ipa_init_teth_stats(struct ipa_teth_stats_endpoints *in)
+{
+ struct ipahal_stats_init_pyld *pyld;
+ struct ipahal_imm_cmd_dma_shared_mem cmd = { 0 };
+ struct ipahal_imm_cmd_pyld *cmd_pyld;
+ struct ipahal_imm_cmd_register_write teth_base = {0};
+ struct ipahal_imm_cmd_pyld *teth_base_pyld;
+ struct ipahal_imm_cmd_register_write teth_mask = { 0 };
+ struct ipahal_imm_cmd_pyld *teth_mask_pyld;
+ struct ipa3_desc desc[3] = { {0} };
+ dma_addr_t dma_address;
+ int ret;
+ int i;
+
+ if (!ipa3_ctx->hw_stats.enabled)
+ return 0;
+
+ if (!in || !in->prod_mask) {
+ IPAERR("invalid params\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < IPA_STATS_MAX_PIPE_BIT; i++) {
+ if ((in->prod_mask & (1 << i)) && !in->dst_ep_mask[i]) {
+ IPAERR("prod %d doesn't have cons\n", i);
+ return -EINVAL;
+ }
+ }
+ IPADBG_LOW("prod_mask=0x%x\n", in->prod_mask);
+
+ /* reset driver's cache */
+ memset(&ipa3_ctx->hw_stats.teth.init, 0,
+ sizeof(ipa3_ctx->hw_stats.teth.init));
+ for (i = 0; i < IPA_CLIENT_MAX; i++)
+ memset(&ipa3_ctx->hw_stats.teth.prod_stats[i], 0,
+ sizeof(ipa3_ctx->hw_stats.teth.prod_stats[i]));
+ ipa3_ctx->hw_stats.teth.init.prod_bitmask = in->prod_mask;
+ memcpy(ipa3_ctx->hw_stats.teth.init.cons_bitmask, in->dst_ep_mask,
+ sizeof(ipa3_ctx->hw_stats.teth.init.cons_bitmask));
+
+
+ pyld = ipahal_stats_generate_init_pyld(IPAHAL_HW_STATS_TETHERING,
+ &ipa3_ctx->hw_stats.teth.init, false);
+ if (!pyld) {
+ IPAERR("failed to generate pyld\n");
+ return -EPERM;
+ }
+
+ if (pyld->len > IPA_MEM_PART(stats_tethering_size)) {
+ IPAERR("SRAM partition too small: %d needed %d\n",
+ IPA_MEM_PART(stats_tethering_size), pyld->len);
+ ret = -EPERM;
+ goto destroy_init_pyld;
+ }
+
+ dma_address = dma_map_single(ipa3_ctx->pdev,
+ pyld->data,
+ pyld->len,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(ipa3_ctx->pdev, dma_address)) {
+ IPAERR("failed to DMA map\n");
+ ret = -EPERM;
+ goto destroy_init_pyld;
+ }
+
+ /* setting the registers and init the stats pyld are done atomically */
+ teth_mask.skip_pipeline_clear = false;
+ teth_mask.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
+ teth_mask.offset = ipahal_get_reg_n_ofst(IPA_STAT_TETHERING_MASK_n,
+ ipa3_ctx->ee);
+ teth_mask.value = in->prod_mask;
+ teth_mask.value_mask = ~0;
+ teth_mask_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_REGISTER_WRITE,
+ &teth_mask, false);
+ if (!teth_mask_pyld) {
+ IPAERR("failed to construct register_write imm cmd\n");
+ ret = -ENOMEM;
+ goto unmap;
+ }
+ desc[0].opcode = teth_mask_pyld->opcode;
+ desc[0].pyld = teth_mask_pyld->data;
+ desc[0].len = teth_mask_pyld->len;
+ desc[0].type = IPA_IMM_CMD_DESC;
+
+ teth_base.skip_pipeline_clear = false;
+ teth_base.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
+ teth_base.offset = ipahal_get_reg_n_ofst(IPA_STAT_TETHERING_BASE_n,
+ ipa3_ctx->ee);
+ teth_base.value = ipa3_ctx->smem_restricted_bytes +
+ IPA_MEM_PART(stats_tethering_ofst);
+ teth_base.value_mask = ~0;
+ teth_base_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_REGISTER_WRITE,
+ &teth_base, false);
+ if (!teth_base_pyld) {
+ IPAERR("failed to construct register_write imm cmd\n");
+ ret = -ENOMEM;
+ goto destroy_teth_mask;
+ }
+ desc[1].opcode = teth_base_pyld->opcode;
+ desc[1].pyld = teth_base_pyld->data;
+ desc[1].len = teth_base_pyld->len;
+ desc[1].type = IPA_IMM_CMD_DESC;
+
+ cmd.is_read = false;
+ cmd.skip_pipeline_clear = false;
+ cmd.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
+ cmd.size = pyld->len;
+ cmd.system_addr = dma_address;
+ cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
+ IPA_MEM_PART(stats_tethering_ofst);
+ cmd_pyld = ipahal_construct_imm_cmd(
+ IPA_IMM_CMD_DMA_SHARED_MEM, &cmd, false);
+ if (!cmd_pyld) {
+ IPAERR("failed to construct dma_shared_mem imm cmd\n");
+ ret = -ENOMEM;
+ goto destroy_teth_base;
+ }
+ desc[2].opcode = cmd_pyld->opcode;
+ desc[2].pyld = cmd_pyld->data;
+ desc[2].len = cmd_pyld->len;
+ desc[2].type = IPA_IMM_CMD_DESC;
+
+ ret = ipa3_send_cmd(3, desc);
+ if (ret) {
+ IPAERR("failed to send immediate command (error %d)\n", ret);
+ goto destroy_imm;
+ }
+
+ ret = 0;
+
+destroy_imm:
+ ipahal_destroy_imm_cmd(cmd_pyld);
+destroy_teth_base:
+ ipahal_destroy_imm_cmd(teth_base_pyld);
+destroy_teth_mask:
+ ipahal_destroy_imm_cmd(teth_mask_pyld);
+unmap:
+ dma_unmap_single(ipa3_ctx->pdev, dma_address, pyld->len, DMA_TO_DEVICE);
+destroy_init_pyld:
+ ipahal_destroy_stats_init_pyld(pyld);
+ return ret;
+}
+
+int ipa_get_teth_stats(enum ipa_client_type prod,
+ struct ipa_quota_stats_all *out)
+{
+ int i, j;
+ int ret;
+ struct ipahal_stats_get_offset_tethering get_offset = { { 0 } };
+ struct ipahal_stats_offset offset = {0};
+ struct ipahal_imm_cmd_dma_shared_mem cmd = { 0 };
+ struct ipahal_imm_cmd_pyld *cmd_pyld;
+ struct ipa_mem_buffer mem;
+ struct ipa3_desc desc = { 0 };
+ struct ipahal_stats_tethering_all *stats;
+
+ if (!ipa3_ctx->hw_stats.enabled)
+ return 0;
+
+ if (!IPA_CLIENT_IS_PROD(prod) || ipa3_get_ep_mapping(prod) == -1) {
+ IPAERR("invalid prod %d\n", prod);
+ return -EINVAL;
+ }
+
+ get_offset.init = ipa3_ctx->hw_stats.teth.init;
+ ret = ipahal_stats_get_offset(IPAHAL_HW_STATS_TETHERING, &get_offset,
+ &offset);
+ if (ret) {
+ IPAERR("failed to get offset from hal %d\n", ret);
+ return ret;
+ }
+
+ IPADBG_LOW("offset = %d size = %d\n", offset.offset, offset.size);
+
+ mem.size = offset.size;
+ mem.base = dma_alloc_coherent(ipa3_ctx->pdev,
+ mem.size,
+ &mem.phys_base,
+ GFP_KERNEL);
+ if (!mem.base) {
+ IPAERR("fail to alloc DMA memory\n");
+ return ret;
+ }
+
+ cmd.is_read = true;
+ cmd.clear_after_read = true;
+ cmd.skip_pipeline_clear = false;
+ cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
+ cmd.size = mem.size;
+ cmd.system_addr = mem.phys_base;
+ cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
+ IPA_MEM_PART(stats_tethering_ofst) + offset.offset;
+ cmd_pyld = ipahal_construct_imm_cmd(
+ IPA_IMM_CMD_DMA_SHARED_MEM, &cmd, false);
+ if (!cmd_pyld) {
+ IPAERR("failed to construct dma_shared_mem imm cmd\n");
+ ret = -ENOMEM;
+ goto free_dma_mem;
+ }
+ desc.opcode = cmd_pyld->opcode;
+ desc.pyld = cmd_pyld->data;
+ desc.len = cmd_pyld->len;
+ desc.type = IPA_IMM_CMD_DESC;
+
+ ret = ipa3_send_cmd(1, &desc);
+ if (ret) {
+ IPAERR("failed to send immediate command (error %d)\n", ret);
+ goto destroy_imm;
+ }
+
+ stats = kzalloc(sizeof(*stats), GFP_KERNEL);
+ if (!stats) {
+ IPADBG("failed to alloc memory\n");
+ ret = -ENOMEM;
+ goto destroy_imm;
+ }
+
+ ret = ipahal_parse_stats(IPAHAL_HW_STATS_TETHERING,
+ &ipa3_ctx->hw_stats.teth.init, mem.base, stats);
+ if (ret) {
+ IPAERR("failed to parse stats (error %d)\n", ret);
+ goto free_stats;
+ }
+
+ /*
+ * update driver cache.
+ * the stats were read from hardware with clear_after_read meaning
+ * hardware stats are 0 now
+ */
+ for (i = 0; i < IPA_CLIENT_MAX; i++) {
+ for (j = 0; j < IPA_CLIENT_MAX; j++) {
+ struct ipa_hw_stats_teth *sw_stats =
+ &ipa3_ctx->hw_stats.teth;
+ int prod_idx = ipa3_get_ep_mapping(i);
+ int cons_idx = ipa3_get_ep_mapping(j);
+
+ if (prod_idx == -1 || prod_idx >= IPA3_MAX_NUM_PIPES)
+ continue;
+
+ if (cons_idx == -1 || cons_idx >= IPA3_MAX_NUM_PIPES)
+ continue;
+
+ if (ipa3_ctx->ep[prod_idx].client != i ||
+ ipa3_ctx->ep[cons_idx].client != j)
+ continue;
+
+ sw_stats->prod_stats[i].client[j].num_ipv4_bytes +=
+ stats->stats[prod_idx][cons_idx].num_ipv4_bytes;
+ sw_stats->prod_stats[i].client[j].num_ipv4_pkts +=
+ stats->stats[prod_idx][cons_idx].num_ipv4_pkts;
+ sw_stats->prod_stats[i].client[j].num_ipv6_bytes +=
+ stats->stats[prod_idx][cons_idx].num_ipv6_bytes;
+ sw_stats->prod_stats[i].client[j].num_ipv6_pkts +=
+ stats->stats[prod_idx][cons_idx].num_ipv6_pkts;
+ }
+ }
+
+ if (!out) {
+ ret = 0;
+ goto free_stats;
+ }
+
+ /* copy results to out parameter */
+ *out = ipa3_ctx->hw_stats.teth.prod_stats[prod];
+
+ ret = 0;
+free_stats:
+ kfree(stats);
+destroy_imm:
+ ipahal_destroy_imm_cmd(cmd_pyld);
+free_dma_mem:
+ dma_free_coherent(ipa3_ctx->pdev, mem.size, mem.base, mem.phys_base);
+ return ret;
+
+}
+
+int ipa_reset_teth_stats(enum ipa_client_type prod, enum ipa_client_type cons)
+{
+ int ret;
+ struct ipa_quota_stats *stats;
+
+ if (!ipa3_ctx->hw_stats.enabled)
+ return 0;
+
+ if (!IPA_CLIENT_IS_PROD(prod) || IPA_CLIENT_IS_CONS(cons) == -1) {
+ IPAERR("invalid prod %d or cons %d\n", prod, cons);
+ return -EINVAL;
+ }
+
+ /* reading stats will reset them in hardware */
+ ret = ipa_get_teth_stats(prod, NULL);
+ if (ret) {
+ IPAERR("ipa_get_teth_stats failed %d\n", ret);
+ return ret;
+ }
+
+ /* reset driver's cache */
+ stats = &ipa3_ctx->hw_stats.teth.prod_stats[prod].client[cons];
+ memset(stats, 0, sizeof(*stats));
+ return 0;
+}
+
+int ipa_reset_all_cons_teth_stats(enum ipa_client_type prod)
+{
+ int ret;
+ int i;
+ struct ipa_quota_stats *stats;
+
+ if (!ipa3_ctx->hw_stats.enabled)
+ return 0;
+
+ if (!IPA_CLIENT_IS_PROD(prod)) {
+ IPAERR("invalid prod %d\n", prod);
+ return -EINVAL;
+ }
+
+ /* reading stats will reset them in hardware */
+ ret = ipa_get_teth_stats(prod, NULL);
+ if (ret) {
+ IPAERR("ipa_get_teth_stats failed %d\n", ret);
+ return ret;
+ }
+
+ /* reset driver's cache */
+ for (i = 0; i < IPA_CLIENT_MAX; i++) {
+ stats = &ipa3_ctx->hw_stats.teth.prod_stats[prod].client[i];
+ memset(stats, 0, sizeof(*stats));
+ }
+
+ return 0;
+}
+
+int ipa_reset_all_teth_stats(void)
+{
+ int i;
+ int ret;
+ struct ipa_quota_stats_all *stats;
+
+ if (!ipa3_ctx->hw_stats.enabled)
+ return 0;
+
+ /* reading stats will reset them in hardware */
+ for (i = 0; i < IPA_CLIENT_MAX; i++) {
+ if (IPA_CLIENT_IS_PROD(i) && ipa3_get_ep_mapping(i) != -1) {
+ ret = ipa_get_teth_stats(i, NULL);
+ if (ret) {
+ IPAERR("ipa_get_teth_stats failed %d\n", ret);
+ return ret;
+ }
+ /* a single iteration will reset all hardware stats */
+ break;
+ }
+ }
+
+ /* reset driver's cache */
+ for (i = 0; i < IPA_CLIENT_MAX; i++) {
+ stats = &ipa3_ctx->hw_stats.teth.prod_stats[i];
+ memset(stats, 0, sizeof(*stats));
+ }
+
+ return 0;
+}
+
+int ipa_flt_rt_stats_add_rule_id(enum ipa_ip_type ip, bool filtering,
+ u16 rule_id)
+{
+ int rule_idx, rule_bit;
+ u32 *bmsk_ptr;
+
+ if (!ipa3_ctx->hw_stats.enabled)
+ return 0;
+
+ if (ip < 0 || ip >= IPA_IP_MAX) {
+ IPAERR("wrong ip type %d\n", ip);
+ return -EINVAL;
+ }
+
+ rule_idx = rule_id / 32;
+ rule_bit = rule_id % 32;
+
+ if (rule_idx >= IPAHAL_MAX_RULE_ID_32) {
+ IPAERR("invalid rule_id %d\n", rule_id);
+ return -EINVAL;
+ }
+
+ if (ip == IPA_IP_v4 && filtering)
+ bmsk_ptr =
+ ipa3_ctx->hw_stats.flt_rt.flt_v4_init.rule_id_bitmask;
+ else if (ip == IPA_IP_v4)
+ bmsk_ptr =
+ ipa3_ctx->hw_stats.flt_rt.rt_v4_init.rule_id_bitmask;
+ else if (ip == IPA_IP_v6 && filtering)
+ bmsk_ptr =
+ ipa3_ctx->hw_stats.flt_rt.flt_v6_init.rule_id_bitmask;
+ else
+ bmsk_ptr =
+ ipa3_ctx->hw_stats.flt_rt.rt_v6_init.rule_id_bitmask;
+
+ bmsk_ptr[rule_idx] |= (1 << rule_bit);
+
+ return 0;
+}
+
+int ipa_flt_rt_stats_start(enum ipa_ip_type ip, bool filtering)
+{
+ struct ipahal_stats_init_pyld *pyld;
+ int smem_ofst, smem_size, stats_base, start_id_ofst, end_id_ofst;
+ int start_id, end_id;
+ struct ipahal_stats_init_flt_rt *init;
+ struct ipahal_imm_cmd_dma_shared_mem cmd = { 0 };
+ struct ipahal_imm_cmd_pyld *cmd_pyld;
+ struct ipahal_imm_cmd_register_write flt_rt_base = {0};
+ struct ipahal_imm_cmd_pyld *flt_rt_base_pyld;
+ struct ipahal_imm_cmd_register_write flt_rt_start_id = {0};
+ struct ipahal_imm_cmd_pyld *flt_rt_start_id_pyld;
+ struct ipahal_imm_cmd_register_write flt_rt_end_id = { 0 };
+ struct ipahal_imm_cmd_pyld *flt_rt_end_id_pyld;
+ struct ipa3_desc desc[4] = { {0} };
+ dma_addr_t dma_address;
+ int ret;
+
+ if (!ipa3_ctx->hw_stats.enabled)
+ return 0;
+
+ if (ip == IPA_IP_v4 && filtering) {
+ init = &ipa3_ctx->hw_stats.flt_rt.flt_v4_init;
+ smem_ofst = IPA_MEM_PART(stats_flt_v4_ofst);
+ smem_size = IPA_MEM_PART(stats_flt_v4_size);
+ stats_base = ipahal_get_reg_ofst(IPA_STAT_FILTER_IPV4_BASE);
+ start_id_ofst =
+ ipahal_get_reg_ofst(IPA_STAT_FILTER_IPV4_START_ID);
+ end_id_ofst = ipahal_get_reg_ofst(IPA_STAT_FILTER_IPV4_END_ID);
+ } else if (ip == IPA_IP_v4) {
+ init = &ipa3_ctx->hw_stats.flt_rt.rt_v4_init;
+ smem_ofst = IPA_MEM_PART(stats_rt_v4_ofst);
+ smem_size = IPA_MEM_PART(stats_rt_v4_size);
+ stats_base = ipahal_get_reg_ofst(IPA_STAT_ROUTER_IPV4_BASE);
+ start_id_ofst =
+ ipahal_get_reg_ofst(IPA_STAT_ROUTER_IPV4_START_ID);
+ end_id_ofst = ipahal_get_reg_ofst(IPA_STAT_ROUTER_IPV4_END_ID);
+ } else if (ip == IPA_IP_v6 && filtering) {
+ init = &ipa3_ctx->hw_stats.flt_rt.flt_v6_init;
+ smem_ofst = IPA_MEM_PART(stats_flt_v6_ofst);
+ smem_size = IPA_MEM_PART(stats_flt_v6_size);
+ stats_base = ipahal_get_reg_ofst(IPA_STAT_FILTER_IPV6_BASE);
+ start_id_ofst =
+ ipahal_get_reg_ofst(IPA_STAT_FILTER_IPV6_START_ID);
+ end_id_ofst = ipahal_get_reg_ofst(IPA_STAT_FILTER_IPV6_END_ID);
+ } else {
+ init = &ipa3_ctx->hw_stats.flt_rt.rt_v6_init;
+ smem_ofst = IPA_MEM_PART(stats_rt_v6_ofst);
+ smem_size = IPA_MEM_PART(stats_rt_v6_size);
+ stats_base = ipahal_get_reg_ofst(IPA_STAT_ROUTER_IPV6_BASE);
+ start_id_ofst =
+ ipahal_get_reg_ofst(IPA_STAT_ROUTER_IPV6_START_ID);
+ end_id_ofst = ipahal_get_reg_ofst(IPA_STAT_ROUTER_IPV6_END_ID);
+ }
+
+ for (start_id = 0; start_id < IPAHAL_MAX_RULE_ID_32; start_id++) {
+ if (init->rule_id_bitmask[start_id])
+ break;
+ }
+
+ if (start_id == IPAHAL_MAX_RULE_ID_32) {
+ IPAERR("empty rule ids\n");
+ return -EINVAL;
+ }
+
+ /* every rule_id_bitmask contains 32 rules */
+ start_id *= 32;
+
+ for (end_id = IPAHAL_MAX_RULE_ID_32 - 1; end_id >= 0; end_id--) {
+ if (init->rule_id_bitmask[end_id])
+ break;
+ }
+ end_id = (end_id + 1) * 32 - 1;
+
+ pyld = ipahal_stats_generate_init_pyld(IPAHAL_HW_STATS_FNR, init,
+ false);
+ if (!pyld) {
+ IPAERR("failed to generate pyld\n");
+ return -EPERM;
+ }
+
+ if (pyld->len > smem_size) {
+ IPAERR("SRAM partition too small: %d needed %d\n",
+ smem_size, pyld->len);
+ ret = -EPERM;
+ goto destroy_init_pyld;
+ }
+
+ dma_address = dma_map_single(ipa3_ctx->pdev,
+ pyld->data,
+ pyld->len,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(ipa3_ctx->pdev, dma_address)) {
+ IPAERR("failed to DMA map\n");
+ ret = -EPERM;
+ goto destroy_init_pyld;
+ }
+
+ /* setting the registers and init the stats pyld are done atomically */
+ flt_rt_start_id.skip_pipeline_clear = false;
+ flt_rt_start_id.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
+ flt_rt_start_id.offset = start_id_ofst;
+ flt_rt_start_id.value = start_id;
+ flt_rt_start_id.value_mask = 0x3FF;
+ flt_rt_start_id_pyld = ipahal_construct_imm_cmd(
+ IPA_IMM_CMD_REGISTER_WRITE, &flt_rt_start_id, false);
+ if (!flt_rt_start_id_pyld) {
+ IPAERR("failed to construct register_write imm cmd\n");
+ ret = -ENOMEM;
+ goto unmap;
+ }
+ desc[0].opcode = flt_rt_start_id_pyld->opcode;
+ desc[0].pyld = flt_rt_start_id_pyld->data;
+ desc[0].len = flt_rt_start_id_pyld->len;
+ desc[0].type = IPA_IMM_CMD_DESC;
+
+ flt_rt_end_id.skip_pipeline_clear = false;
+ flt_rt_end_id.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
+ flt_rt_end_id.offset = end_id_ofst;
+ flt_rt_end_id.value = end_id;
+ flt_rt_end_id.value_mask = 0x3FF;
+ flt_rt_end_id_pyld = ipahal_construct_imm_cmd(
+ IPA_IMM_CMD_REGISTER_WRITE, &flt_rt_end_id, false);
+ if (!flt_rt_end_id_pyld) {
+ IPAERR("failed to construct register_write imm cmd\n");
+ ret = -ENOMEM;
+ goto destroy_flt_rt_start_id;
+ }
+ desc[1].opcode = flt_rt_end_id_pyld->opcode;
+ desc[1].pyld = flt_rt_end_id_pyld->data;
+ desc[1].len = flt_rt_end_id_pyld->len;
+ desc[1].type = IPA_IMM_CMD_DESC;
+
+ flt_rt_base.skip_pipeline_clear = false;
+ flt_rt_base.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
+ flt_rt_base.offset = stats_base;
+ flt_rt_base.value = ipa3_ctx->smem_restricted_bytes +
+ smem_ofst;
+ flt_rt_base.value_mask = ~0;
+ flt_rt_base_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_REGISTER_WRITE,
+ &flt_rt_base, false);
+ if (!flt_rt_base_pyld) {
+ IPAERR("failed to construct register_write imm cmd\n");
+ ret = -ENOMEM;
+ goto destroy_flt_rt_end_id;
+ }
+ desc[2].opcode = flt_rt_base_pyld->opcode;
+ desc[2].pyld = flt_rt_base_pyld->data;
+ desc[2].len = flt_rt_base_pyld->len;
+ desc[2].type = IPA_IMM_CMD_DESC;
+
+ cmd.is_read = false;
+ cmd.skip_pipeline_clear = false;
+ cmd.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
+ cmd.size = pyld->len;
+ cmd.system_addr = dma_address;
+ cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
+ smem_ofst;
+ cmd_pyld = ipahal_construct_imm_cmd(
+ IPA_IMM_CMD_DMA_SHARED_MEM, &cmd, false);
+ if (!cmd_pyld) {
+ IPAERR("failed to construct dma_shared_mem imm cmd\n");
+ ret = -ENOMEM;
+ goto destroy_flt_rt_base;
+ }
+ desc[3].opcode = cmd_pyld->opcode;
+ desc[3].pyld = cmd_pyld->data;
+ desc[3].len = cmd_pyld->len;
+ desc[3].type = IPA_IMM_CMD_DESC;
+
+ ret = ipa3_send_cmd(4, desc);
+ if (ret) {
+ IPAERR("failed to send immediate command (error %d)\n", ret);
+ goto destroy_imm;
+ }
+
+ ret = 0;
+
+destroy_imm:
+ ipahal_destroy_imm_cmd(cmd_pyld);
+destroy_flt_rt_base:
+ ipahal_destroy_imm_cmd(flt_rt_base_pyld);
+destroy_flt_rt_end_id:
+ ipahal_destroy_imm_cmd(flt_rt_end_id_pyld);
+destroy_flt_rt_start_id:
+ ipahal_destroy_imm_cmd(flt_rt_start_id_pyld);
+unmap:
+ dma_unmap_single(ipa3_ctx->pdev, dma_address, pyld->len, DMA_TO_DEVICE);
+destroy_init_pyld:
+ ipahal_destroy_stats_init_pyld(pyld);
+ return ret;
+}
+
+int ipa_flt_rt_stats_clear_rule_ids(enum ipa_ip_type ip, bool filtering)
+{
+ struct ipahal_stats_init_flt_rt *init;
+ int i;
+
+ if (!ipa3_ctx->hw_stats.enabled)
+ return 0;
+
+ if (ip < 0 || ip >= IPA_IP_MAX) {
+ IPAERR("wrong ip type %d\n", ip);
+ return -EINVAL;
+ }
+
+ if (ip == IPA_IP_v4 && filtering)
+ init = &ipa3_ctx->hw_stats.flt_rt.flt_v4_init;
+ else if (ip == IPA_IP_v4)
+ init = &ipa3_ctx->hw_stats.flt_rt.rt_v4_init;
+ else if (ip == IPA_IP_v6 && filtering)
+ init = &ipa3_ctx->hw_stats.flt_rt.flt_v6_init;
+ else
+ init = &ipa3_ctx->hw_stats.flt_rt.rt_v6_init;
+
+ for (i = 0; i < IPAHAL_MAX_RULE_ID_32; i++)
+ init->rule_id_bitmask[i] = 0;
+
+ return 0;
+}
+
+static int __ipa_get_flt_rt_stats(enum ipa_ip_type ip, bool filtering,
+ u16 rule_id, struct ipa_flt_rt_stats *out)
+{
+ int ret;
+ int smem_ofst;
+ bool clear = false;
+ struct ipahal_stats_get_offset_flt_rt *get_offset;
+ struct ipahal_stats_offset offset = { 0 };
+ struct ipahal_imm_cmd_dma_shared_mem cmd = { 0 };
+ struct ipahal_imm_cmd_pyld *cmd_pyld;
+ struct ipa_mem_buffer mem;
+ struct ipa3_desc desc = { 0 };
+ struct ipahal_stats_flt_rt stats;
+
+ if (rule_id >= IPAHAL_MAX_RULE_ID_32 * 32) {
+ IPAERR("invalid rule_id %d\n", rule_id);
+ return -EINVAL;
+ }
+
+ if (out == NULL)
+ clear = true;
+
+ get_offset = kzalloc(sizeof(*get_offset), GFP_KERNEL);
+ if (!get_offset) {
+ IPADBG("no mem\n");
+ return -ENOMEM;
+ }
+
+ if (ip == IPA_IP_v4 && filtering) {
+ get_offset->init = ipa3_ctx->hw_stats.flt_rt.flt_v4_init;
+ smem_ofst = IPA_MEM_PART(stats_flt_v4_ofst);
+ } else if (ip == IPA_IP_v4) {
+ get_offset->init = ipa3_ctx->hw_stats.flt_rt.rt_v4_init;
+ smem_ofst = IPA_MEM_PART(stats_rt_v4_ofst);
+ } else if (ip == IPA_IP_v6 && filtering) {
+ get_offset->init = ipa3_ctx->hw_stats.flt_rt.flt_v6_init;
+ smem_ofst = IPA_MEM_PART(stats_flt_v6_ofst);
+ } else {
+ get_offset->init = ipa3_ctx->hw_stats.flt_rt.rt_v6_init;
+ smem_ofst = IPA_MEM_PART(stats_rt_v6_ofst);
+ }
+
+ get_offset->rule_id = rule_id;
+
+ ret = ipahal_stats_get_offset(IPAHAL_HW_STATS_FNR, get_offset,
+ &offset);
+ if (ret) {
+ IPAERR("failed to get offset from hal %d\n", ret);
+ goto free_offset;
+ }
+
+ IPADBG_LOW("offset = %d size = %d\n", offset.offset, offset.size);
+
+ mem.size = offset.size;
+ mem.base = dma_alloc_coherent(ipa3_ctx->pdev,
+ mem.size,
+ &mem.phys_base,
+ GFP_KERNEL);
+ if (!mem.base) {
+ IPAERR("fail to alloc DMA memory\n");
+ goto free_offset;
+ }
+
+ cmd.is_read = true;
+ cmd.clear_after_read = clear;
+ cmd.skip_pipeline_clear = false;
+ cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
+ cmd.size = mem.size;
+ cmd.system_addr = mem.phys_base;
+ cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
+ smem_ofst + offset.offset;
+ cmd_pyld = ipahal_construct_imm_cmd(
+ IPA_IMM_CMD_DMA_SHARED_MEM, &cmd, false);
+ if (!cmd_pyld) {
+ IPAERR("failed to construct dma_shared_mem imm cmd\n");
+ ret = -ENOMEM;
+ goto free_dma_mem;
+ }
+ desc.opcode = cmd_pyld->opcode;
+ desc.pyld = cmd_pyld->data;
+ desc.len = cmd_pyld->len;
+ desc.type = IPA_IMM_CMD_DESC;
+
+ ret = ipa3_send_cmd(1, &desc);
+ if (ret) {
+ IPAERR("failed to send immediate command (error %d)\n", ret);
+ goto destroy_imm;
+ }
+
+ ret = ipahal_parse_stats(IPAHAL_HW_STATS_FNR,
+ &get_offset->init, mem.base, &stats);
+ if (ret) {
+ IPAERR("failed to parse stats (error %d)\n", ret);
+ goto destroy_imm;
+ }
+
+ if (out) {
+ out->num_pkts = stats.num_packets;
+ out->num_pkts_hash = stats.num_packets_hash;
+ }
+
+ ret = 0;
+
+destroy_imm:
+ ipahal_destroy_imm_cmd(cmd_pyld);
+free_dma_mem:
+ dma_free_coherent(ipa3_ctx->pdev, mem.size, mem.base, mem.phys_base);
+free_offset:
+ kfree(get_offset);
+ return ret;
+
+}
+
+
+int ipa_get_flt_rt_stats(enum ipa_ip_type ip, bool filtering, u16 rule_id,
+ struct ipa_flt_rt_stats *out)
+{
+ if (!ipa3_ctx->hw_stats.enabled)
+ return 0;
+
+ if (ip < 0 || ip >= IPA_IP_MAX) {
+ IPAERR("wrong ip type %d\n", ip);
+ return -EINVAL;
+ }
+
+ return __ipa_get_flt_rt_stats(ip, filtering, rule_id, out);
+}
+
+int ipa_reset_flt_rt_stats(enum ipa_ip_type ip, bool filtering, u16 rule_id)
+{
+ if (!ipa3_ctx->hw_stats.enabled)
+ return 0;
+
+ if (ip < 0 || ip >= IPA_IP_MAX) {
+ IPAERR("wrong ip type %d\n", ip);
+ return -EINVAL;
+ }
+
+ return __ipa_get_flt_rt_stats(ip, filtering, rule_id, NULL);
+}
+
+int ipa_reset_all_flt_rt_stats(enum ipa_ip_type ip, bool filtering)
+{
+ struct ipahal_stats_init_flt_rt *init;
+ int i;
+
+ if (!ipa3_ctx->hw_stats.enabled)
+ return 0;
+
+ if (ip < 0 || ip >= IPA_IP_MAX) {
+ IPAERR("wrong ip type %d\n", ip);
+ return -EINVAL;
+ }
+
+ if (ip == IPA_IP_v4 && filtering)
+ init = &ipa3_ctx->hw_stats.flt_rt.flt_v4_init;
+ else if (ip == IPA_IP_v4)
+ init = &ipa3_ctx->hw_stats.flt_rt.rt_v4_init;
+ else if (ip == IPA_IP_v6 && filtering)
+ init = &ipa3_ctx->hw_stats.flt_rt.flt_v6_init;
+ else
+ init = &ipa3_ctx->hw_stats.flt_rt.rt_v6_init;
+
+ for (i = 0; i < IPAHAL_MAX_RULE_ID_32 * 32; i++) {
+ int idx = i / 32;
+ int bit = i % 32;
+
+ if (init->rule_id_bitmask[idx] & (1 << bit))
+ __ipa_get_flt_rt_stats(ip, filtering, i, NULL);
+ }
+
+ return 0;
+}
+
+int ipa_init_drop_stats(u32 pipe_bitmask)
+{
+ struct ipahal_stats_init_pyld *pyld;
+ struct ipahal_imm_cmd_dma_shared_mem cmd = { 0 };
+ struct ipahal_imm_cmd_pyld *cmd_pyld;
+ struct ipahal_imm_cmd_register_write drop_base = {0};
+ struct ipahal_imm_cmd_pyld *drop_base_pyld;
+ struct ipahal_imm_cmd_register_write drop_mask = {0};
+ struct ipahal_imm_cmd_pyld *drop_mask_pyld;
+ struct ipa3_desc desc[3] = { {0} };
+ dma_addr_t dma_address;
+ int ret;
+
+ if (!ipa3_ctx->hw_stats.enabled)
+ return 0;
+
+ /* reset driver's cache */
+ memset(&ipa3_ctx->hw_stats.drop, 0, sizeof(ipa3_ctx->hw_stats.drop));
+ ipa3_ctx->hw_stats.drop.init.enabled_bitmask = pipe_bitmask;
+ IPADBG_LOW("pipe_bitmask=0x%x\n", pipe_bitmask);
+
+ pyld = ipahal_stats_generate_init_pyld(IPAHAL_HW_STATS_DROP,
+ &ipa3_ctx->hw_stats.drop.init, false);
+ if (!pyld) {
+ IPAERR("failed to generate pyld\n");
+ return -EPERM;
+ }
+
+ if (pyld->len > IPA_MEM_PART(stats_drop_size)) {
+ IPAERR("SRAM partition too small: %d needed %d\n",
+ IPA_MEM_PART(stats_drop_size), pyld->len);
+ ret = -EPERM;
+ goto destroy_init_pyld;
+ }
+
+ dma_address = dma_map_single(ipa3_ctx->pdev,
+ pyld->data,
+ pyld->len,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(ipa3_ctx->pdev, dma_address)) {
+ IPAERR("failed to DMA map\n");
+ ret = -EPERM;
+ goto destroy_init_pyld;
+ }
+
+ /* setting the registers and init the stats pyld are done atomically */
+ drop_mask.skip_pipeline_clear = false;
+ drop_mask.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
+ drop_mask.offset = ipahal_get_reg_n_ofst(IPA_STAT_DROP_CNT_MASK_n,
+ ipa3_ctx->ee);
+ drop_mask.value = pipe_bitmask;
+ drop_mask.value_mask = ~0;
+ drop_mask_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_REGISTER_WRITE,
+ &drop_mask, false);
+ if (!drop_mask_pyld) {
+ IPAERR("failed to construct register_write imm cmd\n");
+ ret = -ENOMEM;
+ goto unmap;
+ }
+ desc[0].opcode = drop_mask_pyld->opcode;
+ desc[0].pyld = drop_mask_pyld->data;
+ desc[0].len = drop_mask_pyld->len;
+ desc[0].type = IPA_IMM_CMD_DESC;
+
+ drop_base.skip_pipeline_clear = false;
+ drop_base.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
+ drop_base.offset = ipahal_get_reg_n_ofst(IPA_STAT_DROP_CNT_BASE_n,
+ ipa3_ctx->ee);
+ drop_base.value = ipa3_ctx->smem_restricted_bytes +
+ IPA_MEM_PART(stats_drop_ofst);
+ drop_base.value_mask = ~0;
+ drop_base_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_REGISTER_WRITE,
+ &drop_base, false);
+ if (!drop_base_pyld) {
+ IPAERR("failed to construct register_write imm cmd\n");
+ ret = -ENOMEM;
+ goto destroy_drop_mask;
+ }
+ desc[1].opcode = drop_base_pyld->opcode;
+ desc[1].pyld = drop_base_pyld->data;
+ desc[1].len = drop_base_pyld->len;
+ desc[1].type = IPA_IMM_CMD_DESC;
+
+ cmd.is_read = false;
+ cmd.skip_pipeline_clear = false;
+ cmd.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
+ cmd.size = pyld->len;
+ cmd.system_addr = dma_address;
+ cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
+ IPA_MEM_PART(stats_drop_ofst);
+ cmd_pyld = ipahal_construct_imm_cmd(
+ IPA_IMM_CMD_DMA_SHARED_MEM, &cmd, false);
+ if (!cmd_pyld) {
+ IPAERR("failed to construct dma_shared_mem imm cmd\n");
+ ret = -ENOMEM;
+ goto destroy_drop_base;
+ }
+ desc[2].opcode = cmd_pyld->opcode;
+ desc[2].pyld = cmd_pyld->data;
+ desc[2].len = cmd_pyld->len;
+ desc[2].type = IPA_IMM_CMD_DESC;
+
+ ret = ipa3_send_cmd(3, desc);
+ if (ret) {
+ IPAERR("failed to send immediate command (error %d)\n", ret);
+ goto destroy_imm;
+ }
+
+ ret = 0;
+
+destroy_imm:
+ ipahal_destroy_imm_cmd(cmd_pyld);
+destroy_drop_base:
+ ipahal_destroy_imm_cmd(drop_base_pyld);
+destroy_drop_mask:
+ ipahal_destroy_imm_cmd(drop_mask_pyld);
+unmap:
+ dma_unmap_single(ipa3_ctx->pdev, dma_address, pyld->len, DMA_TO_DEVICE);
+destroy_init_pyld:
+ ipahal_destroy_stats_init_pyld(pyld);
+ return ret;
+}
+
+int ipa_get_drop_stats(struct ipa_drop_stats_all *out)
+{
+ int i;
+ int ret;
+ struct ipahal_stats_get_offset_drop get_offset = { { 0 } };
+ struct ipahal_stats_offset offset = { 0 };
+ struct ipahal_imm_cmd_dma_shared_mem cmd = { 0 };
+ struct ipahal_imm_cmd_pyld *cmd_pyld;
+ struct ipa_mem_buffer mem;
+ struct ipa3_desc desc = { 0 };
+ struct ipahal_stats_drop_all *stats;
+
+ if (!ipa3_ctx->hw_stats.enabled)
+ return 0;
+
+ get_offset.init = ipa3_ctx->hw_stats.drop.init;
+ ret = ipahal_stats_get_offset(IPAHAL_HW_STATS_DROP, &get_offset,
+ &offset);
+ if (ret) {
+ IPAERR("failed to get offset from hal %d\n", ret);
+ return ret;
+ }
+
+ IPADBG_LOW("offset = %d size = %d\n", offset.offset, offset.size);
+
+ mem.size = offset.size;
+ mem.base = dma_alloc_coherent(ipa3_ctx->pdev,
+ mem.size,
+ &mem.phys_base,
+ GFP_KERNEL);
+ if (!mem.base) {
+ IPAERR("fail to alloc DMA memory\n");
+ return ret;
+ }
+
+ cmd.is_read = true;
+ cmd.clear_after_read = true;
+ cmd.skip_pipeline_clear = false;
+ cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
+ cmd.size = mem.size;
+ cmd.system_addr = mem.phys_base;
+ cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
+ IPA_MEM_PART(stats_drop_ofst) + offset.offset;
+ cmd_pyld = ipahal_construct_imm_cmd(
+ IPA_IMM_CMD_DMA_SHARED_MEM, &cmd, false);
+ if (!cmd_pyld) {
+ IPAERR("failed to construct dma_shared_mem imm cmd\n");
+ ret = -ENOMEM;
+ goto free_dma_mem;
+ }
+ desc.opcode = cmd_pyld->opcode;
+ desc.pyld = cmd_pyld->data;
+ desc.len = cmd_pyld->len;
+ desc.type = IPA_IMM_CMD_DESC;
+
+ ret = ipa3_send_cmd(1, &desc);
+ if (ret) {
+ IPAERR("failed to send immediate command (error %d)\n", ret);
+ goto destroy_imm;
+ }
+
+ stats = kzalloc(sizeof(*stats), GFP_KERNEL);
+ if (!stats) {
+ IPADBG("failed to alloc memory\n");
+ ret = -ENOMEM;
+ goto destroy_imm;
+ }
+
+ ret = ipahal_parse_stats(IPAHAL_HW_STATS_DROP,
+ &ipa3_ctx->hw_stats.drop.init, mem.base, stats);
+ if (ret) {
+ IPAERR("failed to parse stats (error %d)\n", ret);
+ goto free_stats;
+ }
+
+ /*
+ * update driver cache.
+ * the stats were read from hardware with clear_after_read meaning
+ * hardware stats are 0 now
+ */
+ for (i = 0; i < IPA_CLIENT_MAX; i++) {
+ int ep_idx = ipa3_get_ep_mapping(i);
+
+ if (ep_idx == -1 || ep_idx >= IPA3_MAX_NUM_PIPES)
+ continue;
+
+ if (ipa3_ctx->ep[ep_idx].client != i)
+ continue;
+
+ ipa3_ctx->hw_stats.drop.stats.client[i].drop_byte_cnt +=
+ stats->stats[ep_idx].drop_byte_cnt;
+ ipa3_ctx->hw_stats.drop.stats.client[i].drop_packet_cnt +=
+ stats->stats[ep_idx].drop_packet_cnt;
+ }
+
+
+ if (!out) {
+ ret = 0;
+ goto free_stats;
+ }
+
+ /* copy results to out parameter */
+ *out = ipa3_ctx->hw_stats.drop.stats;
+
+ ret = 0;
+free_stats:
+ kfree(stats);
+destroy_imm:
+ ipahal_destroy_imm_cmd(cmd_pyld);
+free_dma_mem:
+ dma_free_coherent(ipa3_ctx->pdev, mem.size, mem.base, mem.phys_base);
+ return ret;
+
+}
+
+int ipa_reset_drop_stats(enum ipa_client_type client)
+{
+ int ret;
+ struct ipa_drop_stats *stats;
+
+ if (client >= IPA_CLIENT_MAX) {
+ IPAERR("invalid client %d\n", client);
+ return -EINVAL;
+ }
+
+ /* reading stats will reset them in hardware */
+ ret = ipa_get_drop_stats(NULL);
+ if (ret) {
+ IPAERR("ipa_get_drop_stats failed %d\n", ret);
+ return ret;
+ }
+
+ /* reset driver's cache */
+ stats = &ipa3_ctx->hw_stats.drop.stats.client[client];
+ memset(stats, 0, sizeof(*stats));
+ return 0;
+}
+
+int ipa_reset_all_drop_stats(void)
+{
+ int ret;
+ struct ipa_drop_stats_all *stats;
+
+ if (!ipa3_ctx->hw_stats.enabled)
+ return 0;
+
+ /* reading stats will reset them in hardware */
+ ret = ipa_get_drop_stats(NULL);
+ if (ret) {
+ IPAERR("ipa_get_drop_stats failed %d\n", ret);
+ return ret;
+ }
+
+ /* reset driver's cache */
+ stats = &ipa3_ctx->hw_stats.drop.stats;
+ memset(stats, 0, sizeof(*stats));
+ return 0;
+}
+
+
+#ifndef CONFIG_DEBUG_FS
+int ipa_debugfs_init_stats(struct dentry *parent) { return 0; }
+#else
+#define IPA_MAX_MSG_LEN 4096
+static char dbg_buff[IPA_MAX_MSG_LEN];
+
+static ssize_t ipa_debugfs_reset_quota_stats(struct file *file,
+ const char __user *ubuf, size_t count, loff_t *ppos)
+{
+ unsigned long missing;
+ s8 client = 0;
+ int ret;
+
+ mutex_lock(&ipa3_ctx->lock);
+ if (sizeof(dbg_buff) < count + 1) {
+ ret = -EFAULT;
+ goto bail;
+ }
+
+ missing = copy_from_user(dbg_buff, ubuf, count);
+ if (missing) {
+ ret = -EFAULT;
+ goto bail;
+ }
+
+ dbg_buff[count] = '\0';
+ if (kstrtos8(dbg_buff, 0, &client)) {
+ ret = -EFAULT;
+ goto bail;
+ }
+
+ if (client == -1)
+ ipa_reset_all_quota_stats();
+ else
+ ipa_reset_quota_stats(client);
+
+ ret = count;
+bail:
+ mutex_unlock(&ipa3_ctx->lock);
+ return ret;
+}
+
+static ssize_t ipa_debugfs_print_quota_stats(struct file *file,
+ char __user *ubuf, size_t count, loff_t *ppos)
+{
+ int nbytes = 0;
+ struct ipa_quota_stats_all *out;
+ int i;
+ int res;
+
+ out = kzalloc(sizeof(*out), GFP_KERNEL);
+ if (!out)
+ return -ENOMEM;
+
+ mutex_lock(&ipa3_ctx->lock);
+ res = ipa_get_quota_stats(out);
+ if (res) {
+ mutex_unlock(&ipa3_ctx->lock);
+ kfree(out);
+ return res;
+ }
+ for (i = 0; i < IPA_CLIENT_MAX; i++) {
+ int ep_idx = ipa3_get_ep_mapping(i);
+
+ if (ep_idx == -1)
+ continue;
+
+ if (IPA_CLIENT_IS_TEST(i))
+ continue;
+
+ if (!(ipa3_ctx->hw_stats.quota.init.enabled_bitmask &
+ (1 << ep_idx)))
+ continue;
+
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "%s:\n",
+ ipa_clients_strings[i]);
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "num_ipv4_bytes=%llu\n",
+ out->client[i].num_ipv4_bytes);
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "num_ipv6_bytes=%llu\n",
+ out->client[i].num_ipv6_bytes);
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "num_ipv4_pkts=%u\n",
+ out->client[i].num_ipv4_pkts);
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "num_ipv6_pkts=%u\n",
+ out->client[i].num_ipv6_pkts);
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "\n");
+
+ }
+ mutex_unlock(&ipa3_ctx->lock);
+ kfree(out);
+
+ return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
+}
+
+static ssize_t ipa_debugfs_reset_tethering_stats(struct file *file,
+ const char __user *ubuf, size_t count, loff_t *ppos)
+{
+ unsigned long missing;
+ s8 client = 0;
+ int ret;
+
+ mutex_lock(&ipa3_ctx->lock);
+ if (sizeof(dbg_buff) < count + 1) {
+ ret = -EFAULT;
+ goto bail;
+ }
+
+ missing = copy_from_user(dbg_buff, ubuf, count);
+ if (missing) {
+ ret = -EFAULT;
+ goto bail;
+ }
+
+ dbg_buff[count] = '\0';
+ if (kstrtos8(dbg_buff, 0, &client)) {
+ ret = -EFAULT;
+ goto bail;
+ }
+
+ if (client == -1)
+ ipa_reset_all_teth_stats();
+ else
+ ipa_reset_all_cons_teth_stats(client);
+
+ ret = count;
+bail:
+ mutex_unlock(&ipa3_ctx->lock);
+ return ret;
+}
+
+static ssize_t ipa_debugfs_print_tethering_stats(struct file *file,
+ char __user *ubuf, size_t count, loff_t *ppos)
+{
+ int nbytes = 0;
+ struct ipa_quota_stats_all *out;
+ int i, j;
+ int res;
+
+ out = kzalloc(sizeof(*out), GFP_KERNEL);
+ if (!out)
+ return -ENOMEM;
+
+ mutex_lock(&ipa3_ctx->lock);
+ for (i = 0; i < IPA_CLIENT_MAX; i++) {
+ int ep_idx = ipa3_get_ep_mapping(i);
+
+ if (ep_idx == -1)
+ continue;
+
+ if (!IPA_CLIENT_IS_PROD(i))
+ continue;
+
+ if (IPA_CLIENT_IS_TEST(i))
+ continue;
+
+ if (!(ipa3_ctx->hw_stats.teth.init.prod_bitmask &
+ (1 << ep_idx)))
+ continue;
+
+ res = ipa_get_teth_stats(i, out);
+ if (res) {
+ mutex_unlock(&ipa3_ctx->lock);
+ kfree(out);
+ return res;
+ }
+
+ for (j = 0; j < IPA_CLIENT_MAX; j++) {
+ int cons_idx = ipa3_get_ep_mapping(j);
+
+ if (cons_idx == -1)
+ continue;
+
+ if (IPA_CLIENT_IS_TEST(j))
+ continue;
+
+ if (!(ipa3_ctx->hw_stats.teth.init.cons_bitmask[ep_idx]
+ & (1 << cons_idx)))
+ continue;
+
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "%s->%s:\n",
+ ipa_clients_strings[i],
+ ipa_clients_strings[j]);
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "num_ipv4_bytes=%llu\n",
+ out->client[j].num_ipv4_bytes);
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "num_ipv6_bytes=%llu\n",
+ out->client[j].num_ipv6_bytes);
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "num_ipv4_pkts=%u\n",
+ out->client[j].num_ipv4_pkts);
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "num_ipv6_pkts=%u\n",
+ out->client[j].num_ipv6_pkts);
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "\n");
+ }
+ }
+ mutex_unlock(&ipa3_ctx->lock);
+ kfree(out);
+
+ return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
+}
+
+static ssize_t ipa_debugfs_control_flt_rt_stats(enum ipa_ip_type ip,
+ bool filtering, struct file *file,
+ const char __user *ubuf, size_t count, loff_t *ppos)
+{
+ unsigned long missing;
+ u16 rule_id = 0;
+ int ret;
+
+ mutex_lock(&ipa3_ctx->lock);
+ if (sizeof(dbg_buff) < count + 1) {
+ ret = -EFAULT;
+ goto bail;
+ }
+
+ missing = copy_from_user(dbg_buff, ubuf, count);
+ if (missing) {
+ ret = -EFAULT;
+ goto bail;
+ }
+
+ dbg_buff[count] = '\0';
+ if (strcmp(dbg_buff, "start\n") == 0) {
+ ipa_flt_rt_stats_start(ip, filtering);
+ } else if (strcmp(dbg_buff, "clear\n") == 0) {
+ ipa_flt_rt_stats_clear_rule_ids(ip, filtering);
+ } else if (strcmp(dbg_buff, "reset\n") == 0) {
+ ipa_reset_all_flt_rt_stats(ip, filtering);
+ } else {
+ if (kstrtou16(dbg_buff, 0, &rule_id)) {
+ ret = -EFAULT;
+ goto bail;
+ }
+ ipa_flt_rt_stats_add_rule_id(ip, filtering, rule_id);
+ }
+
+ ret = count;
+bail:
+ mutex_unlock(&ipa3_ctx->lock);
+ return ret;
+}
+
+static ssize_t ipa_debugfs_print_flt_rt_stats(enum ipa_ip_type ip,
+ bool filtering, struct file *file,
+ char __user *ubuf, size_t count, loff_t *ppos)
+{
+ int nbytes = 0;
+ struct ipahal_stats_init_flt_rt *init;
+ struct ipa_flt_rt_stats out;
+ int i;
+ int res;
+
+ if (ip == IPA_IP_v4 && filtering)
+ init = &ipa3_ctx->hw_stats.flt_rt.flt_v4_init;
+ else if (ip == IPA_IP_v4)
+ init = &ipa3_ctx->hw_stats.flt_rt.rt_v4_init;
+ else if (ip == IPA_IP_v6 && filtering)
+ init = &ipa3_ctx->hw_stats.flt_rt.flt_v6_init;
+ else
+ init = &ipa3_ctx->hw_stats.flt_rt.rt_v6_init;
+
+ mutex_lock(&ipa3_ctx->lock);
+ for (i = 0; i < IPAHAL_MAX_RULE_ID_32 * 32; i++) {
+ int idx = i / 32;
+ int bit = i % 32;
+
+ if (init->rule_id_bitmask[idx] & (1 << bit)) {
+ res = ipa_get_flt_rt_stats(ip, filtering, i, &out);
+ if (res) {
+ mutex_unlock(&ipa3_ctx->lock);
+ return res;
+ }
+
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "rule_id: %d\n", i);
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "num_pkts: %d\n",
+ out.num_pkts);
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "num_pkts_hash: %d\n",
+ out.num_pkts_hash);
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "\n");
+ }
+ }
+
+ mutex_unlock(&ipa3_ctx->lock);
+
+ return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
+}
+
+static ssize_t ipa_debugfs_reset_drop_stats(struct file *file,
+ const char __user *ubuf, size_t count, loff_t *ppos)
+{
+ unsigned long missing;
+ s8 client = 0;
+ int ret;
+
+ mutex_lock(&ipa3_ctx->lock);
+ if (sizeof(dbg_buff) < count + 1) {
+ ret = -EFAULT;
+ goto bail;
+ }
+
+ missing = copy_from_user(dbg_buff, ubuf, count);
+ if (missing) {
+ ret = -EFAULT;
+ goto bail;
+ }
+
+ dbg_buff[count] = '\0';
+ if (kstrtos8(dbg_buff, 0, &client)) {
+ ret = -EFAULT;
+ goto bail;
+ }
+
+ if (client == -1)
+ ipa_reset_all_drop_stats();
+ else
+ ipa_reset_drop_stats(client);
+
+ ret = count;
+bail:
+ mutex_unlock(&ipa3_ctx->lock);
+ return count;
+}
+
+static ssize_t ipa_debugfs_print_drop_stats(struct file *file,
+ char __user *ubuf, size_t count, loff_t *ppos)
+{
+ int nbytes = 0;
+ struct ipa_drop_stats_all *out;
+ int i;
+ int res;
+
+ out = kzalloc(sizeof(*out), GFP_KERNEL);
+ if (!out)
+ return -ENOMEM;
+
+ mutex_lock(&ipa3_ctx->lock);
+ res = ipa_get_drop_stats(out);
+ if (res) {
+ mutex_unlock(&ipa3_ctx->lock);
+ kfree(out);
+ return res;
+ }
+
+ for (i = 0; i < IPA_CLIENT_MAX; i++) {
+ int ep_idx = ipa3_get_ep_mapping(i);
+
+ if (ep_idx == -1)
+ continue;
+
+ if (!IPA_CLIENT_IS_CONS(i))
+ continue;
+
+ if (IPA_CLIENT_IS_TEST(i))
+ continue;
+
+ if (!(ipa3_ctx->hw_stats.drop.init.enabled_bitmask &
+ (1 << ep_idx)))
+ continue;
+
+
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "%s:\n",
+ ipa_clients_strings[i]);
+
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "drop_byte_cnt=%u\n",
+ out->client[i].drop_byte_cnt);
+
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "drop_packet_cnt=%u\n",
+ out->client[i].drop_packet_cnt);
+ nbytes += scnprintf(dbg_buff + nbytes,
+ IPA_MAX_MSG_LEN - nbytes,
+ "\n");
+ }
+ mutex_unlock(&ipa3_ctx->lock);
+ kfree(out);
+
+ return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
+}
+
+static ssize_t ipa_debugfs_control_flt_v4_stats(struct file *file,
+ const char __user *ubuf, size_t count, loff_t *ppos)
+{
+ return ipa_debugfs_control_flt_rt_stats(IPA_IP_v4, true, file, ubuf,
+ count, ppos);
+}
+
+static ssize_t ipa_debugfs_control_flt_v6_stats(struct file *file,
+ const char __user *ubuf, size_t count, loff_t *ppos)
+{
+ return ipa_debugfs_control_flt_rt_stats(IPA_IP_v6, true, file, ubuf,
+ count, ppos);
+}
+
+static ssize_t ipa_debugfs_control_rt_v4_stats(struct file *file,
+ const char __user *ubuf, size_t count, loff_t *ppos)
+{
+ return ipa_debugfs_control_flt_rt_stats(IPA_IP_v4, false, file, ubuf,
+ count, ppos);
+}
+
+static ssize_t ipa_debugfs_control_rt_v6_stats(struct file *file,
+ const char __user *ubuf, size_t count, loff_t *ppos)
+{
+ return ipa_debugfs_control_flt_rt_stats(IPA_IP_v6, false, file, ubuf,
+ count, ppos);
+}
+
+static ssize_t ipa_debugfs_print_flt_v4_stats(struct file *file,
+ char __user *ubuf, size_t count, loff_t *ppos)
+{
+ return ipa_debugfs_print_flt_rt_stats(IPA_IP_v4, true, file, ubuf,
+ count, ppos);
+}
+
+static ssize_t ipa_debugfs_print_flt_v6_stats(struct file *file,
+ char __user *ubuf, size_t count, loff_t *ppos)
+{
+ return ipa_debugfs_print_flt_rt_stats(IPA_IP_v6, true, file, ubuf,
+ count, ppos);
+}
+
+static ssize_t ipa_debugfs_print_rt_v4_stats(struct file *file,
+ char __user *ubuf, size_t count, loff_t *ppos)
+{
+ return ipa_debugfs_print_flt_rt_stats(IPA_IP_v4, false, file, ubuf,
+ count, ppos);
+}
+
+static ssize_t ipa_debugfs_print_rt_v6_stats(struct file *file,
+ char __user *ubuf, size_t count, loff_t *ppos)
+{
+ return ipa_debugfs_print_flt_rt_stats(IPA_IP_v6, false, file, ubuf,
+ count, ppos);
+}
+
+static const struct file_operations ipa3_quota_ops = {
+ .read = ipa_debugfs_print_quota_stats,
+ .write = ipa_debugfs_reset_quota_stats,
+};
+
+static const struct file_operations ipa3_tethering_ops = {
+ .read = ipa_debugfs_print_tethering_stats,
+ .write = ipa_debugfs_reset_tethering_stats,
+};
+
+static const struct file_operations ipa3_flt_v4_ops = {
+ .read = ipa_debugfs_print_flt_v4_stats,
+ .write = ipa_debugfs_control_flt_v4_stats,
+};
+
+static const struct file_operations ipa3_flt_v6_ops = {
+ .read = ipa_debugfs_print_flt_v6_stats,
+ .write = ipa_debugfs_control_flt_v6_stats,
+};
+
+static const struct file_operations ipa3_rt_v4_ops = {
+ .read = ipa_debugfs_print_rt_v4_stats,
+ .write = ipa_debugfs_control_rt_v4_stats,
+};
+
+static const struct file_operations ipa3_rt_v6_ops = {
+ .read = ipa_debugfs_print_rt_v6_stats,
+ .write = ipa_debugfs_control_rt_v6_stats,
+};
+
+static const struct file_operations ipa3_drop_ops = {
+ .read = ipa_debugfs_print_drop_stats,
+ .write = ipa_debugfs_reset_drop_stats,
+};
+
+
+int ipa_debugfs_init_stats(struct dentry *parent)
+{
+ const mode_t read_write_mode = 0664;
+ struct dentry *file;
+ struct dentry *dent;
+
+ if (!ipa3_ctx->hw_stats.enabled)
+ return 0;
+
+ dent = debugfs_create_dir("hw_stats", parent);
+ if (IS_ERR_OR_NULL(dent)) {
+ IPAERR("fail to create folder in debug_fs\n");
+ return -EFAULT;
+ }
+
+ file = debugfs_create_file("quota", read_write_mode, dent, NULL,
+ &ipa3_quota_ops);
+ if (IS_ERR_OR_NULL(file)) {
+ IPAERR("fail to create file %s\n", "quota");
+ goto fail;
+ }
+
+ file = debugfs_create_file("drop", read_write_mode, dent, NULL,
+ &ipa3_drop_ops);
+ if (IS_ERR_OR_NULL(file)) {
+ IPAERR("fail to create file %s\n", "drop");
+ goto fail;
+ }
+
+ file = debugfs_create_file("tethering", read_write_mode, dent, NULL,
+ &ipa3_tethering_ops);
+ if (IS_ERR_OR_NULL(file)) {
+ IPAERR("fail to create file %s\n", "tethering");
+ goto fail;
+ }
+
+ file = debugfs_create_file("flt_v4", read_write_mode, dent, NULL,
+ &ipa3_flt_v4_ops);
+ if (IS_ERR_OR_NULL(file)) {
+ IPAERR("fail to create file %s\n", "flt_v4");
+ goto fail;
+ }
+
+ file = debugfs_create_file("flt_v6", read_write_mode, dent, NULL,
+ &ipa3_flt_v6_ops);
+ if (IS_ERR_OR_NULL(file)) {
+ IPAERR("fail to create file %s\n", "flt_v6");
+ goto fail;
+ }
+
+ file = debugfs_create_file("rt_v4", read_write_mode, dent, NULL,
+ &ipa3_rt_v4_ops);
+ if (IS_ERR_OR_NULL(file)) {
+ IPAERR("fail to create file %s\n", "rt_v4");
+ goto fail;
+ }
+
+ file = debugfs_create_file("rt_v6", read_write_mode, dent, NULL,
+ &ipa3_rt_v6_ops);
+ if (IS_ERR_OR_NULL(file)) {
+ IPAERR("fail to create file %s\n", "rt_v6");
+ goto fail;
+ }
+
+ return 0;
+fail:
+ debugfs_remove_recursive(dent);
+ return -EFAULT;
+}
+#endif
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
index 58702e9..96a022d 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
@@ -33,6 +33,7 @@
#include "ipahal/ipahal_reg.h"
#include "ipahal/ipahal.h"
#include "ipahal/ipahal_fltrt.h"
+#include "ipahal/ipahal_hw_stats.h"
#include "../ipa_common_i.h"
#include "ipa_uc_offload_i.h"
@@ -251,7 +252,7 @@
* @curr_mem: current routing tables block in sys memory
* @prev_mem: previous routing table block in sys memory
* @id: routing table id
- * @rule_ids: idr structure that holds the rule_id for each rule
+ * @rule_ids: common idr structure that holds the rule_id for each rule
*/
struct ipa3_rt_tbl {
struct list_head link;
@@ -267,7 +268,7 @@
struct ipa_mem_buffer curr_mem[IPA_RULE_TYPE_MAX];
struct ipa_mem_buffer prev_mem[IPA_RULE_TYPE_MAX];
int id;
- struct idr rule_ids;
+ struct idr *rule_ids;
};
/**
@@ -389,7 +390,7 @@
* @end: the last header index
* @curr_mem: current filter tables block in sys memory
* @prev_mem: previous filter table block in sys memory
- * @rule_ids: idr structure that holds the rule_id for each rule
+ * @rule_ids: common idr structure that holds the rule_id for each rule
*/
struct ipa3_flt_tbl {
struct list_head head_flt_rule_list;
@@ -399,7 +400,7 @@
struct ipa_mem_buffer curr_mem[IPA_RULE_TYPE_MAX];
struct ipa_mem_buffer prev_mem[IPA_RULE_TYPE_MAX];
bool sticky_rear;
- struct idr rule_ids;
+ struct idr *rule_ids;
};
/**
@@ -433,10 +434,12 @@
* struct ipa3_rt_tbl_set - collection of routing tables
* @head_rt_tbl_list: collection of routing tables
* @tbl_cnt: number of routing tables
+ * @rule_ids: idr structure that holds the rule_id for each rule
*/
struct ipa3_rt_tbl_set {
struct list_head head_rt_tbl_list;
u32 tbl_cnt;
+ struct idr rule_ids;
};
/**
@@ -1035,6 +1038,56 @@
struct ipahal_imm_cmd_pyld *cmd_pyld;
};
+struct ipa_quota_stats {
+ u64 num_ipv4_bytes;
+ u64 num_ipv6_bytes;
+ u32 num_ipv4_pkts;
+ u32 num_ipv6_pkts;
+};
+
+struct ipa_quota_stats_all {
+ struct ipa_quota_stats client[IPA_CLIENT_MAX];
+};
+
+struct ipa_drop_stats {
+ u32 drop_packet_cnt;
+ u32 drop_byte_cnt;
+};
+
+struct ipa_drop_stats_all {
+ struct ipa_drop_stats client[IPA_CLIENT_MAX];
+};
+
+struct ipa_hw_stats_quota {
+ struct ipahal_stats_init_quota init;
+ struct ipa_quota_stats_all stats;
+};
+
+struct ipa_hw_stats_teth {
+ struct ipahal_stats_init_tethering init;
+ struct ipa_quota_stats_all prod_stats[IPA_CLIENT_MAX];
+};
+
+struct ipa_hw_stats_flt_rt {
+ struct ipahal_stats_init_flt_rt flt_v4_init;
+ struct ipahal_stats_init_flt_rt flt_v6_init;
+ struct ipahal_stats_init_flt_rt rt_v4_init;
+ struct ipahal_stats_init_flt_rt rt_v6_init;
+};
+
+struct ipa_hw_stats_drop {
+ struct ipahal_stats_init_drop init;
+ struct ipa_drop_stats_all stats;
+};
+
+struct ipa_hw_stats {
+ bool enabled;
+ struct ipa_hw_stats_quota quota;
+ struct ipa_hw_stats_teth teth;
+ struct ipa_hw_stats_flt_rt flt_rt;
+ struct ipa_hw_stats_drop drop;
+};
+
/**
* struct ipa3_context - IPA context
* @class: pointer to the struct class
@@ -1048,6 +1101,7 @@
* @ep_flt_num: End-points supporting filtering number
* @resume_on_connect: resume ep on ipa connect
* @flt_tbl: list of all IPA filter tables
+ * @flt_rule_ids: idr structure that holds the rule_id for each rule
* @mode: IPA operating mode
* @mmio: iomem
* @ipa_wrapper_base: IPA wrapper base address
@@ -1133,6 +1187,7 @@
u32 ep_flt_num;
bool resume_on_connect[IPA_CLIENT_MAX];
struct ipa3_flt_tbl flt_tbl[IPA3_MAX_NUM_PIPES][IPA_IP_MAX];
+ struct idr flt_rule_ids[IPA_IP_MAX];
void __iomem *mmio;
u32 ipa_wrapper_base;
u32 ipa_wrapper_size;
@@ -1247,6 +1302,7 @@
u32 ipa_tz_unlock_reg_num;
struct ipa_tz_unlock_reg_info *ipa_tz_unlock_reg;
struct ipa_dma_task_info dma_task_info;
+ struct ipa_hw_stats hw_stats;
};
struct ipa3_plat_drv_res {
@@ -1359,6 +1415,48 @@
* +-------------------------+
* | CANARY |
* +-------------------------+
+ * | QUOTA STATS |
+ * +-------------------------+
+ * | CANARY |
+ * +-------------------------+
+ * | CANARY |
+ * +-------------------------+
+ * | TETH STATS |
+ * +-------------------------+
+ * | CANARY |
+ * +-------------------------+
+ * | CANARY |
+ * +-------------------------+
+ * | V4 FLT STATS |
+ * +-------------------------+
+ * | CANARY |
+ * +-------------------------+
+ * | CANARY |
+ * +-------------------------+
+ * | V6 FLT STATS |
+ * +-------------------------+
+ * | CANARY |
+ * +-------------------------+
+ * | CANARY |
+ * +-------------------------+
+ * | V4 RT STATS |
+ * +-------------------------+
+ * | CANARY |
+ * +-------------------------+
+ * | CANARY |
+ * +-------------------------+
+ * | V6 RT STATS |
+ * +-------------------------+
+ * | CANARY |
+ * +-------------------------+
+ * | CANARY |
+ * +-------------------------+
+ * | DROP STATS |
+ * +-------------------------+
+ * | CANARY |
+ * +-------------------------+
+ * | CANARY |
+ * +-------------------------+
* | MODEM MEM |
* +-------------------------+
* | CANARY |
@@ -1441,6 +1539,20 @@
u32 uc_event_ring_size;
u32 pdn_config_ofst;
u32 pdn_config_size;
+ u32 stats_quota_ofst;
+ u32 stats_quota_size;
+ u32 stats_tethering_ofst;
+ u32 stats_tethering_size;
+ u32 stats_flt_v4_ofst;
+ u32 stats_flt_v4_size;
+ u32 stats_flt_v6_ofst;
+ u32 stats_flt_v6_size;
+ u32 stats_rt_v4_ofst;
+ u32 stats_rt_v4_size;
+ u32 stats_rt_v6_ofst;
+ u32 stats_rt_v6_size;
+ u32 stats_drop_ofst;
+ u32 stats_drop_size;
};
struct ipa3_controller {
@@ -1987,6 +2099,65 @@
(enum ipa_client_type client);
void ipa3_uc_rg10_write_reg(enum ipahal_reg_name reg, u32 n, u32 val);
+/* Hardware stats */
+
+#define IPA_STATS_MAX_PIPE_BIT 32
+
+struct ipa_teth_stats_endpoints {
+ u32 prod_mask;
+ u32 dst_ep_mask[IPA_STATS_MAX_PIPE_BIT];
+};
+
+struct ipa_flt_rt_stats {
+ u32 num_pkts;
+ u32 num_pkts_hash;
+};
+
+int ipa_hw_stats_init(void);
+
+int ipa_debugfs_init_stats(struct dentry *parent);
+
+int ipa_init_quota_stats(u32 pipe_bitmask);
+
+int ipa_get_quota_stats(struct ipa_quota_stats_all *out);
+
+int ipa_reset_quota_stats(enum ipa_client_type client);
+
+int ipa_reset_all_quota_stats(void);
+
+int ipa_init_drop_stats(u32 pipe_bitmask);
+
+int ipa_get_drop_stats(struct ipa_drop_stats_all *out);
+
+int ipa_reset_drop_stats(enum ipa_client_type client);
+
+int ipa_reset_all_drop_stats(void);
+
+int ipa_init_teth_stats(struct ipa_teth_stats_endpoints *in);
+
+int ipa_get_teth_stats(enum ipa_client_type prod,
+ struct ipa_quota_stats_all *out);
+
+int ipa_reset_teth_stats(enum ipa_client_type prod, enum ipa_client_type cons);
+
+int ipa_reset_all_cons_teth_stats(enum ipa_client_type prod);
+
+int ipa_reset_all_teth_stats(void);
+
+int ipa_flt_rt_stats_add_rule_id(enum ipa_ip_type ip, bool filtering,
+ u16 rule_id);
+
+int ipa_flt_rt_stats_start(enum ipa_ip_type ip, bool filtering);
+
+int ipa_flt_rt_stats_clear_rule_ids(enum ipa_ip_type ip, bool filtering);
+
+int ipa_get_flt_rt_stats(enum ipa_ip_type ip, bool filtering, u16 rule_id,
+ struct ipa_flt_rt_stats *out);
+
+int ipa_reset_flt_rt_stats(enum ipa_ip_type ip, bool filtering, u16 rule_id);
+
+int ipa_reset_all_flt_rt_stats(enum ipa_ip_type ip, bool filtering);
+
u32 ipa3_get_num_pipes(void);
struct ipa_smmu_cb_ctx *ipa3_get_smmu_ctx(void);
struct ipa_smmu_cb_ctx *ipa3_get_wlan_smmu_ctx(void);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c
index 80c3996..61bccc6 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c
@@ -808,6 +808,11 @@
return -EINVAL;
}
+ if (req->source_pipe_index == -1) {
+ IPAWANERR("Source pipe index invalid\n");
+ return -EINVAL;
+ }
+
mutex_lock(&ipa3_qmi_lock);
if (ipa3_qmi_ctx != NULL) {
/* cache the qmi_filter_request */
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
index 5f14032..ef0158e 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
@@ -801,7 +801,7 @@
!ipa3_ctx->ip4_rt_tbl_nhash_lcl :
!ipa3_ctx->ip6_rt_tbl_nhash_lcl;
set->tbl_cnt++;
- idr_init(&entry->rule_ids);
+ entry->rule_ids = &set->rule_ids;
list_add(&entry->link, &set->head_rt_tbl_list);
IPADBG("add rt tbl idx=%d tbl_cnt=%d ip=%d\n", entry->idx,
@@ -820,7 +820,7 @@
ipa_insert_failed:
set->tbl_cnt--;
list_del(&entry->link);
- idr_destroy(&entry->rule_ids);
+ idr_destroy(entry->rule_ids);
fail_rt_idx_alloc:
entry->cookie = 0;
kmem_cache_free(ipa3_ctx->rt_tbl_cache, entry);
@@ -855,7 +855,7 @@
rset = &ipa3_ctx->reap_rt_tbl_set[ip];
- idr_destroy(&entry->rule_ids);
+ entry->rule_ids = NULL;
if (entry->in_sys[IPA_RULE_HASHABLE] ||
entry->in_sys[IPA_RULE_NON_HASHABLE]) {
list_move(&entry->link, &rset->head_rt_tbl_list);
@@ -923,7 +923,7 @@
(*(entry))->tbl = tbl;
(*(entry))->hdr = hdr;
(*(entry))->proc_ctx = proc_ctx;
- id = ipa3_alloc_rule_id(&tbl->rule_ids);
+ id = ipa3_alloc_rule_id(tbl->rule_ids);
if (id < 0) {
IPAERR("failed to allocate rule id\n");
WARN_ON(1);
@@ -967,7 +967,7 @@
entry->hdr->ref_cnt--;
else if (entry->proc_ctx)
entry->proc_ctx->ref_cnt--;
- idr_remove(&tbl->rule_ids, entry->rule_id);
+ idr_remove(tbl->rule_ids, entry->rule_id);
list_del(&entry->link);
kmem_cache_free(ipa3_ctx->rt_rule_cache, entry);
return -EPERM;
@@ -1219,7 +1219,7 @@
IPADBG("del rt rule tbl_idx=%d rule_cnt=%d rule_id=%d\n ref_cnt=%u",
entry->tbl->idx, entry->tbl->rule_cnt,
entry->rule_id, entry->tbl->ref_cnt);
- idr_remove(&entry->tbl->rule_ids, entry->rule_id);
+ idr_remove(entry->tbl->rule_ids, entry->rule_id);
if (entry->tbl->rule_cnt == 0 && entry->tbl->ref_cnt == 0) {
if (__ipa_del_rt_tbl(entry->tbl))
IPAERR_RL("fail to del RT tbl\n");
@@ -1378,7 +1378,7 @@
else if (rule->proc_ctx)
__ipa3_release_hdr_proc_ctx(rule->proc_ctx->id);
rule->cookie = 0;
- idr_remove(&tbl->rule_ids, rule->rule_id);
+ idr_remove(tbl->rule_ids, rule->rule_id);
id = rule->id;
kmem_cache_free(ipa3_ctx->rt_rule_cache, rule);
@@ -1395,7 +1395,7 @@
/* do not remove the "default" routing tbl which has index 0 */
if (tbl->idx != apps_start_idx) {
- idr_destroy(&tbl->rule_ids);
+ tbl->rule_ids = NULL;
if (tbl->in_sys[IPA_RULE_HASHABLE] ||
tbl->in_sys[IPA_RULE_NON_HASHABLE]) {
list_move(&tbl->link, &rset->head_rt_tbl_list);
@@ -1444,6 +1444,10 @@
mutex_lock(&ipa3_ctx->lock);
entry = __ipa3_find_rt_tbl(lookup->ip, lookup->name);
if (entry && entry->cookie == IPA_RT_TBL_COOKIE) {
+ if (entry->ref_cnt == U32_MAX) {
+ IPAERR("fail: ref count crossed limit\n");
+ goto ret;
+ }
entry->ref_cnt++;
lookup->hdl = entry->id;
@@ -1453,6 +1457,8 @@
result = 0;
}
+
+ret:
mutex_unlock(&ipa3_ctx->lock);
return result;
@@ -1470,7 +1476,7 @@
{
struct ipa3_rt_tbl *entry;
enum ipa_ip_type ip = IPA_IP_MAX;
- int result;
+ int result = 0;
mutex_lock(&ipa3_ctx->lock);
entry = ipa3_id_find(rt_tbl_hdl);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index 1a99808..8fe15bc 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -21,6 +21,7 @@
#include "ipa_i.h"
#include "ipahal/ipahal.h"
#include "ipahal/ipahal_fltrt.h"
+#include "ipahal/ipahal_hw_stats.h"
#include "../ipa_rm_i.h"
#define IPA_V3_0_CLK_RATE_SVS (75 * 1000 * 1000UL)
@@ -1141,7 +1142,7 @@
[IPA_4_0][IPA_CLIENT_ODU_PROD] = {
true, IPA_v4_0_GROUP_UL_DL,
true,
- IPA_DPS_HPS_SEQ_TYPE_DMA_ONLY,
+ IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 1, 0, 8, 16, IPA_EE_AP } },
[IPA_4_0][IPA_CLIENT_ETHERNET_PROD] = {
@@ -4061,7 +4062,7 @@
IPAHAL_FULL_PIPELINE_CLEAR;
reg_write_agg_close.offset =
ipahal_get_reg_ofst(IPA_AGGR_FORCE_CLOSE);
- ipahal_get_aggr_force_close_valmask(1<<i, &valmask);
+ ipahal_get_aggr_force_close_valmask(i, &valmask);
reg_write_agg_close.value = valmask.val;
reg_write_agg_close.value_mask = valmask.mask;
cmd_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_REGISTER_WRITE,
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/Makefile b/drivers/platform/msm/ipa/ipa_v3/ipahal/Makefile
index b945eb06..67e491b 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/Makefile
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/Makefile
@@ -1,3 +1,3 @@
obj-$(CONFIG_IPA3) += ipa_hal.o
-ipa_hal-y := ipahal.o ipahal_reg.o ipahal_fltrt.o
+ipa_hal-y := ipahal.o ipahal_reg.o ipahal_fltrt.o ipahal_hw_stats.o
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c
index 57d44e3..c4b1f35 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c
@@ -15,6 +15,8 @@
#include "ipahal_i.h"
#include "ipahal_reg_i.h"
#include "ipahal_fltrt_i.h"
+#include "ipahal_hw_stats_i.h"
+
struct ipahal_context *ipahal_ctx;
@@ -48,9 +50,6 @@
__stringify(IPAHAL_PKT_STATUS_EXCEPTION_IPV6CT),
};
-#define IPAHAL_MEM_ALLOC(__size, __is_atomic_ctx) \
- (kzalloc((__size), ((__is_atomic_ctx)?GFP_ATOMIC:GFP_KERNEL)))
-
static u16 ipahal_imm_cmd_get_opcode(enum ipahal_imm_cmd_name cmd);
@@ -1504,6 +1503,12 @@
goto bail_free_ctx;
}
+ if (ipahal_hw_stats_init(ipa_hw_type)) {
+ IPAHAL_ERR("failed to init ipahal hw stats\n");
+ result = -EFAULT;
+ goto bail_free_ctx;
+ }
+
ipahal_debugfs_init();
return 0;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_hw_stats.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_hw_stats.c
new file mode 100644
index 0000000..c711ff4
--- /dev/null
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_hw_stats.c
@@ -0,0 +1,557 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "ipahal_hw_stats.h"
+#include "ipahal_hw_stats_i.h"
+#include "ipahal_i.h"
+
+struct ipahal_hw_stats_obj {
+ struct ipahal_stats_init_pyld *(*generate_init_pyld)(void *params,
+ bool is_atomic_ctx);
+ int (*get_offset)(void *params, struct ipahal_stats_offset *out);
+ int (*parse_stats)(void *init_params, void *raw_stats,
+ void *parsed_stats);
+};
+
+static int _count_ones(u32 number)
+{
+ int count = 0;
+
+ while (number) {
+ count++;
+ number = number & (number - 1);
+ }
+
+ return count;
+}
+
+static struct ipahal_stats_init_pyld *ipahal_generate_init_pyld_quota(
+ void *params, bool is_atomic_ctx)
+{
+ struct ipahal_stats_init_pyld *pyld;
+ struct ipahal_stats_init_quota *in =
+ (struct ipahal_stats_init_quota *)params;
+ int entries = _count_ones(in->enabled_bitmask);
+
+ IPAHAL_DBG_LOW("entries = %d\n", entries);
+ pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) +
+ entries * sizeof(struct ipahal_stats_quota_hw), is_atomic_ctx);
+ if (!pyld) {
+ IPAHAL_ERR("no mem\n");
+ return NULL;
+ }
+
+ pyld->len = entries * sizeof(struct ipahal_stats_quota_hw);
+ return pyld;
+}
+
+static int ipahal_get_offset_quota(void *params,
+ struct ipahal_stats_offset *out)
+{
+ struct ipahal_stats_get_offset_quota *in =
+ (struct ipahal_stats_get_offset_quota *)params;
+ int entries = _count_ones(in->init.enabled_bitmask);
+
+ IPAHAL_DBG_LOW("\n");
+ out->offset = 0;
+ out->size = entries * sizeof(struct ipahal_stats_quota_hw);
+
+ return 0;
+}
+
+static int ipahal_parse_stats_quota(void *init_params, void *raw_stats,
+ void *parsed_stats)
+{
+ struct ipahal_stats_init_quota *init =
+ (struct ipahal_stats_init_quota *)init_params;
+ struct ipahal_stats_quota_hw *raw_hw =
+ (struct ipahal_stats_quota_hw *)raw_stats;
+ struct ipahal_stats_quota_all *out =
+ (struct ipahal_stats_quota_all *)parsed_stats;
+ int stat_idx = 0;
+ int i;
+
+ memset(out, 0, sizeof(*out));
+ IPAHAL_DBG_LOW("\n");
+ for (i = 0; i < IPAHAL_MAX_PIPES; i++) {
+ if (init->enabled_bitmask & (1 << i)) {
+ IPAHAL_DBG_LOW("pipe %d stat_idx %d\n", i, stat_idx);
+ out->stats[i].num_ipv4_bytes =
+ raw_hw[stat_idx].num_ipv4_bytes;
+ out->stats[i].num_ipv4_pkts =
+ raw_hw[stat_idx].num_ipv4_pkts;
+ out->stats[i].num_ipv6_pkts =
+ raw_hw[stat_idx].num_ipv6_pkts;
+ out->stats[i].num_ipv6_bytes =
+ raw_hw[stat_idx].num_ipv6_bytes;
+ stat_idx++;
+ }
+ }
+
+ return 0;
+}
+
+static struct ipahal_stats_init_pyld *ipahal_generate_init_pyld_tethering(
+ void *params, bool is_atomic_ctx)
+{
+ struct ipahal_stats_init_pyld *pyld;
+ struct ipahal_stats_init_tethering *in =
+ (struct ipahal_stats_init_tethering *)params;
+ int hdr_entries = _count_ones(in->prod_bitmask);
+ int entries = 0;
+ int i;
+ void *pyld_ptr;
+ u32 incremental_offset;
+
+ IPAHAL_DBG_LOW("prod entries = %d\n", hdr_entries);
+ for (i = 0; i < sizeof(in->prod_bitmask) * 8; i++) {
+ if (in->prod_bitmask & (1 << i)) {
+ if (in->cons_bitmask[i] == 0) {
+ IPAHAL_ERR("no cons bitmask for prod %d\n", i);
+ return NULL;
+ }
+ entries += _count_ones(in->cons_bitmask[i]);
+ }
+ }
+ IPAHAL_DBG_LOW("sum all entries = %d\n", entries);
+
+ pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) +
+ hdr_entries * sizeof(struct ipahal_stats_tethering_hdr_hw) +
+ entries * sizeof(struct ipahal_stats_tethering_hw),
+ is_atomic_ctx);
+ if (!pyld) {
+ IPAHAL_ERR("no mem\n");
+ return NULL;
+ }
+
+ pyld->len = hdr_entries * sizeof(struct ipahal_stats_tethering_hdr_hw) +
+ entries * sizeof(struct ipahal_stats_tethering_hw);
+
+ pyld_ptr = pyld->data;
+ incremental_offset =
+ (hdr_entries * sizeof(struct ipahal_stats_tethering_hdr_hw))
+ / 8;
+ for (i = 0; i < sizeof(in->prod_bitmask) * 8; i++) {
+ if (in->prod_bitmask & (1 << i)) {
+ struct ipahal_stats_tethering_hdr_hw *hdr = pyld_ptr;
+
+ hdr->dst_mask = in->cons_bitmask[i];
+ hdr->offset = incremental_offset;
+ IPAHAL_DBG_LOW("hdr->dst_mask=0x%x\n", hdr->dst_mask);
+ IPAHAL_DBG_LOW("hdr->offset=0x%x\n", hdr->offset);
+ /* add the stats entry */
+ incremental_offset += _count_ones(in->cons_bitmask[i]) *
+ sizeof(struct ipahal_stats_tethering_hw) / 8;
+ pyld_ptr += sizeof(*hdr);
+ }
+ }
+
+ return pyld;
+}
+
+static int ipahal_get_offset_tethering(void *params,
+ struct ipahal_stats_offset *out)
+{
+ struct ipahal_stats_get_offset_tethering *in =
+ (struct ipahal_stats_get_offset_tethering *)params;
+ int entries = 0;
+ int i;
+
+ for (i = 0; i < sizeof(in->init.prod_bitmask) * 8; i++) {
+ if (in->init.prod_bitmask & (1 << i)) {
+ if (in->init.cons_bitmask[i] == 0) {
+ IPAHAL_ERR("no cons bitmask for prod %d\n", i);
+ return -EPERM;
+ }
+ entries += _count_ones(in->init.cons_bitmask[i]);
+ }
+ }
+ IPAHAL_DBG_LOW("sum all entries = %d\n", entries);
+
+ /* skip the header */
+ out->offset = _count_ones(in->init.prod_bitmask) *
+ sizeof(struct ipahal_stats_tethering_hdr_hw);
+ out->size = entries * sizeof(struct ipahal_stats_tethering_hw);
+
+ return 0;
+}
+
+static int ipahal_parse_stats_tethering(void *init_params, void *raw_stats,
+ void *parsed_stats)
+{
+ struct ipahal_stats_init_tethering *init =
+ (struct ipahal_stats_init_tethering *)init_params;
+ struct ipahal_stats_tethering_hw *raw_hw =
+ (struct ipahal_stats_tethering_hw *)raw_stats;
+ struct ipahal_stats_tethering_all *out =
+ (struct ipahal_stats_tethering_all *)parsed_stats;
+ int i, j;
+ int stat_idx = 0;
+
+ memset(out, 0, sizeof(*out));
+ IPAHAL_DBG_LOW("\n");
+ for (i = 0; i < IPAHAL_MAX_PIPES; i++) {
+ for (j = 0; j < IPAHAL_MAX_PIPES; j++) {
+ if ((init->prod_bitmask & (1 << i)) &&
+ init->cons_bitmask[i] & (1 << j)) {
+ IPAHAL_DBG_LOW("prod %d cons %d\n", i, j);
+ IPAHAL_DBG_LOW("stat_idx %d\n", stat_idx);
+ out->stats[i][j].num_ipv4_bytes =
+ raw_hw[stat_idx].num_ipv4_bytes;
+ IPAHAL_DBG_LOW("num_ipv4_bytes %lld\n",
+ out->stats[i][j].num_ipv4_bytes);
+ out->stats[i][j].num_ipv4_pkts =
+ raw_hw[stat_idx].num_ipv4_pkts;
+ IPAHAL_DBG_LOW("num_ipv4_pkts %lld\n",
+ out->stats[i][j].num_ipv4_pkts);
+ out->stats[i][j].num_ipv6_pkts =
+ raw_hw[stat_idx].num_ipv6_pkts;
+ IPAHAL_DBG_LOW("num_ipv6_pkts %lld\n",
+ out->stats[i][j].num_ipv6_pkts);
+ out->stats[i][j].num_ipv6_bytes =
+ raw_hw[stat_idx].num_ipv6_bytes;
+ IPAHAL_DBG_LOW("num_ipv6_bytes %lld\n",
+ out->stats[i][j].num_ipv6_bytes);
+ stat_idx++;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static struct ipahal_stats_init_pyld *ipahal_generate_init_pyld_flt_rt(
+ void *params, bool is_atomic_ctx)
+{
+ struct ipahal_stats_init_pyld *pyld;
+ struct ipahal_stats_init_flt_rt *in =
+ (struct ipahal_stats_init_flt_rt *)params;
+ int hdr_entries;
+ int num_rules = 0;
+ int i, start_entry;
+ void *pyld_ptr;
+ u32 incremental_offset;
+
+ for (i = 0; i < IPAHAL_MAX_RULE_ID_32; i++)
+ num_rules += _count_ones(in->rule_id_bitmask[i]);
+
+ if (num_rules == 0) {
+ IPAHAL_ERR("no rule ids provided\n");
+ return NULL;
+ }
+ IPAHAL_DBG_LOW("num_rules = %d\n", num_rules);
+
+ hdr_entries = IPAHAL_MAX_RULE_ID_32;
+ for (i = 0; i < IPAHAL_MAX_RULE_ID_32; i++) {
+ if (in->rule_id_bitmask[i] != 0)
+ break;
+ hdr_entries--;
+ }
+ start_entry = i;
+
+ for (i = IPAHAL_MAX_RULE_ID_32 - 1; i >= start_entry; i--) {
+ if (in->rule_id_bitmask[i] != 0)
+ break;
+ hdr_entries--;
+ }
+ IPAHAL_DBG_LOW("hdr_entries = %d\n", hdr_entries);
+
+ pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) +
+ hdr_entries * sizeof(struct ipahal_stats_flt_rt_hdr_hw) +
+ num_rules * sizeof(struct ipahal_stats_flt_rt_hw),
+ is_atomic_ctx);
+ if (!pyld) {
+ IPAHAL_ERR("no mem\n");
+ return NULL;
+ }
+
+ pyld->len = hdr_entries * sizeof(struct ipahal_stats_flt_rt_hdr_hw) +
+ num_rules * sizeof(struct ipahal_stats_flt_rt_hw);
+
+ pyld_ptr = pyld->data;
+ incremental_offset =
+ (hdr_entries * sizeof(struct ipahal_stats_flt_rt_hdr_hw))
+ / 8;
+ for (i = start_entry; i < hdr_entries; i++) {
+ struct ipahal_stats_flt_rt_hdr_hw *hdr = pyld_ptr;
+
+ hdr->en_mask = in->rule_id_bitmask[i];
+ hdr->cnt_offset = incremental_offset;
+ /* add the stats entry */
+ incremental_offset += _count_ones(in->rule_id_bitmask[i]) *
+ sizeof(struct ipahal_stats_flt_rt_hw) / 8;
+ pyld_ptr += sizeof(*hdr);
+ }
+
+ return pyld;
+}
+
+static int ipahal_get_offset_flt_rt(void *params,
+ struct ipahal_stats_offset *out)
+{
+ struct ipahal_stats_get_offset_flt_rt *in =
+ (struct ipahal_stats_get_offset_flt_rt *)params;
+ int i;
+ int hdr_entries;
+ int skip_rules = 0;
+ int start_entry;
+ int rule_bit = in->rule_id % 32;
+ int rule_idx = in->rule_id / 32;
+
+ if (rule_idx >= IPAHAL_MAX_RULE_ID_32) {
+ IPAHAL_ERR("invalid rule_id %d\n", in->rule_id);
+ return -EPERM;
+ }
+
+ hdr_entries = IPAHAL_MAX_RULE_ID_32;
+ for (i = 0; i < IPAHAL_MAX_RULE_ID_32; i++) {
+ if (in->init.rule_id_bitmask[i] != 0)
+ break;
+ hdr_entries--;
+ }
+
+ if (hdr_entries == 0) {
+ IPAHAL_ERR("no rule ids provided\n");
+ return -EPERM;
+ }
+ start_entry = i;
+
+ for (i = IPAHAL_MAX_RULE_ID_32 - 1; i >= 0; i--) {
+ if (in->init.rule_id_bitmask[i] != 0)
+ break;
+ hdr_entries--;
+ }
+ IPAHAL_DBG_LOW("hdr_entries = %d\n", hdr_entries);
+
+ /* skip the header */
+ out->offset = hdr_entries * sizeof(struct ipahal_stats_flt_rt_hdr_hw);
+
+ /* skip the previous rules */
+ for (i = start_entry; i < rule_idx; i++)
+ skip_rules += _count_ones(in->init.rule_id_bitmask[i]);
+
+ for (i = 0; i < rule_bit; i++)
+ if (in->init.rule_id_bitmask[rule_idx] & (1 << i))
+ skip_rules++;
+
+ out->offset += skip_rules * sizeof(struct ipahal_stats_flt_rt_hw);
+ out->size = sizeof(struct ipahal_stats_flt_rt_hw);
+
+ return 0;
+}
+
+static int ipahal_parse_stats_flt_rt(void *init_params, void *raw_stats,
+ void *parsed_stats)
+{
+ struct ipahal_stats_flt_rt_hw *raw_hw =
+ (struct ipahal_stats_flt_rt_hw *)raw_stats;
+ struct ipahal_stats_flt_rt *out =
+ (struct ipahal_stats_flt_rt *)parsed_stats;
+
+ memset(out, 0, sizeof(*out));
+ IPAHAL_DBG_LOW("\n");
+ out->num_packets = raw_hw->num_packets;
+ out->num_packets_hash = raw_hw->num_packets_hash;
+
+ return 0;
+}
+
+static struct ipahal_stats_init_pyld *ipahal_generate_init_pyld_drop(
+ void *params, bool is_atomic_ctx)
+{
+ struct ipahal_stats_init_pyld *pyld;
+ struct ipahal_stats_init_drop *in =
+ (struct ipahal_stats_init_drop *)params;
+ int entries = _count_ones(in->enabled_bitmask);
+
+ IPAHAL_DBG_LOW("entries = %d\n", entries);
+ pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) +
+ entries * sizeof(struct ipahal_stats_drop_hw), is_atomic_ctx);
+ if (!pyld) {
+ IPAHAL_ERR("no mem\n");
+ return NULL;
+ }
+
+ pyld->len = entries * sizeof(struct ipahal_stats_drop_hw);
+
+ return pyld;
+}
+
+static int ipahal_get_offset_drop(void *params,
+ struct ipahal_stats_offset *out)
+{
+ struct ipahal_stats_get_offset_drop *in =
+ (struct ipahal_stats_get_offset_drop *)params;
+ int entries = _count_ones(in->init.enabled_bitmask);
+
+ IPAHAL_DBG_LOW("\n");
+ out->offset = 0;
+ out->size = entries * sizeof(struct ipahal_stats_drop_hw);
+
+ return 0;
+}
+
+static int ipahal_parse_stats_drop(void *init_params, void *raw_stats,
+ void *parsed_stats)
+{
+ struct ipahal_stats_init_drop *init =
+ (struct ipahal_stats_init_drop *)init_params;
+ struct ipahal_stats_drop_hw *raw_hw =
+ (struct ipahal_stats_drop_hw *)raw_stats;
+ struct ipahal_stats_drop_all *out =
+ (struct ipahal_stats_drop_all *)parsed_stats;
+ int stat_idx = 0;
+ int i;
+
+ memset(out, 0, sizeof(*out));
+ IPAHAL_DBG_LOW("\n");
+ for (i = 0; i < IPAHAL_MAX_PIPES; i++) {
+ if (init->enabled_bitmask & (1 << i)) {
+ out->stats[i].drop_byte_cnt =
+ raw_hw[stat_idx].drop_byte_cnt;
+ out->stats[i].drop_packet_cnt =
+ raw_hw[stat_idx].drop_packet_cnt;
+ stat_idx++;
+ }
+ }
+
+ return 0;
+}
+
+static struct ipahal_hw_stats_obj
+ ipahal_hw_stats_objs[IPA_HW_MAX][IPAHAL_HW_STATS_MAX] = {
+ /* IPAv4 */
+ [IPA_HW_v4_0][IPAHAL_HW_STATS_QUOTA] = {
+ ipahal_generate_init_pyld_quota,
+ ipahal_get_offset_quota,
+ ipahal_parse_stats_quota
+ },
+ [IPA_HW_v4_0][IPAHAL_HW_STATS_TETHERING] = {
+ ipahal_generate_init_pyld_tethering,
+ ipahal_get_offset_tethering,
+ ipahal_parse_stats_tethering
+ },
+ [IPA_HW_v4_0][IPAHAL_HW_STATS_FNR] = {
+ ipahal_generate_init_pyld_flt_rt,
+ ipahal_get_offset_flt_rt,
+ ipahal_parse_stats_flt_rt
+ },
+ [IPA_HW_v4_0][IPAHAL_HW_STATS_DROP] = {
+ ipahal_generate_init_pyld_drop,
+ ipahal_get_offset_drop,
+ ipahal_parse_stats_drop
+ },
+};
+
+int ipahal_hw_stats_init(enum ipa_hw_type ipa_hw_type)
+{
+ int i;
+ int j;
+ struct ipahal_hw_stats_obj zero_obj;
+
+ IPAHAL_DBG_LOW("Entry - HW_TYPE=%d\n", ipa_hw_type);
+
+ if ((ipa_hw_type < 0) || (ipa_hw_type >= IPA_HW_MAX)) {
+ IPAHAL_ERR("invalid IPA HW type (%d)\n", ipa_hw_type);
+ return -EINVAL;
+ }
+
+ memset(&zero_obj, 0, sizeof(zero_obj));
+ for (i = IPA_HW_v4_0 ; i < ipa_hw_type ; i++) {
+ for (j = 0; j < IPAHAL_HW_STATS_MAX; j++) {
+ if (!memcmp(&ipahal_hw_stats_objs[i + 1][j], &zero_obj,
+ sizeof(struct ipahal_hw_stats_obj))) {
+ memcpy(&ipahal_hw_stats_objs[i + 1][j],
+ &ipahal_hw_stats_objs[i][j],
+ sizeof(struct ipahal_hw_stats_obj));
+ } else {
+ /*
+ * explicitly overridden stat.
+ * Check validity
+ */
+ if (!ipahal_hw_stats_objs[i + 1][j].
+ get_offset) {
+ IPAHAL_ERR(
+ "stat=%d get_offset null ver=%d\n",
+ j, i+1);
+ WARN_ON(1);
+ }
+ if (!ipahal_hw_stats_objs[i + 1][j].
+ parse_stats) {
+ IPAHAL_ERR(
+ "stat=%d parse_stats null ver=%d\n",
+ j, i + 1);
+ WARN_ON(1);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+int ipahal_stats_get_offset(enum ipahal_hw_stats_type type, void *params,
+ struct ipahal_stats_offset *out)
+{
+ if (type < 0 || type >= IPAHAL_HW_STATS_MAX) {
+ IPAHAL_ERR("Invalid type stat=%d\n", type);
+ WARN_ON(1);
+ return -EFAULT;
+ }
+
+ if (!params || !out) {
+ IPAHAL_ERR("Null arg\n");
+ WARN_ON(1);
+ return -EFAULT;
+ }
+
+ return ipahal_hw_stats_objs[ipahal_ctx->hw_type][type].get_offset(
+ params, out);
+}
+
+struct ipahal_stats_init_pyld *ipahal_stats_generate_init_pyld(
+ enum ipahal_hw_stats_type type, void *params, bool is_atomic_ctx)
+{
+ if (type < 0 || type >= IPAHAL_HW_STATS_MAX) {
+ IPAHAL_ERR("Invalid type stat=%d\n", type);
+ WARN_ON(1);
+ return NULL;
+ }
+
+ if (!params) {
+ IPAHAL_ERR("Null arg\n");
+ WARN_ON(1);
+ return NULL;
+ }
+
+ return ipahal_hw_stats_objs[ipahal_ctx->hw_type][type].
+ generate_init_pyld(params, is_atomic_ctx);
+}
+
+int ipahal_parse_stats(enum ipahal_hw_stats_type type, void *init_params,
+ void *raw_stats, void *parsed_stats)
+{
+ if (type < 0 || type >= IPAHAL_HW_STATS_MAX) {
+ IPAHAL_ERR("Invalid type stat=%d\n", type);
+ WARN_ON(1);
+ return -EFAULT;
+ }
+
+ if (!raw_stats || !parsed_stats) {
+ IPAHAL_ERR("Null arg\n");
+ WARN_ON(1);
+ return -EFAULT;
+ }
+
+ return ipahal_hw_stats_objs[ipahal_ctx->hw_type][type].parse_stats(
+ init_params, raw_stats, parsed_stats);
+}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_hw_stats.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_hw_stats.h
new file mode 100644
index 0000000..cbb1dc3
--- /dev/null
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_hw_stats.h
@@ -0,0 +1,248 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _IPAHAL_HW_STATS_H_
+#define _IPAHAL_HW_STATS_H_
+
+#include <linux/ipa.h>
+
+#define IPAHAL_MAX_PIPES 32
+#define IPAHAL_MAX_RULE_ID_32 (1024 / 32) /* 10 bits of rule id */
+
+enum ipahal_hw_stats_type {
+ IPAHAL_HW_STATS_QUOTA,
+ IPAHAL_HW_STATS_TETHERING,
+ IPAHAL_HW_STATS_FNR,
+ IPAHAL_HW_STATS_DROP,
+ IPAHAL_HW_STATS_MAX
+};
+
+/*
+ * struct ipahal_stats_init_pyld - Statistics initialization payload
+ * @len: length of payload
+ * @data: actual payload data
+ */
+struct ipahal_stats_init_pyld {
+ u16 len;
+ u16 reserved;
+ u8 data[0];
+};
+
+/*
+ * struct ipahal_stats_offset - Statistics offset parameters
+ * @offset: offset of the statistic from beginning of stats table
+ * @size: size of the statistics
+ */
+struct ipahal_stats_offset {
+ u32 offset;
+ u16 size;
+};
+
+/*
+ * struct ipahal_stats_init_quota - Initializations parameters for quota
+ * @enabled_bitmask: bit mask of pipes to be monitored
+ */
+struct ipahal_stats_init_quota {
+ u32 enabled_bitmask;
+};
+
+/*
+ * struct ipahal_stats_get_offset_quota - Get offset parameters for quota
+ * @init: initialization parameters used in initialization of stats
+ */
+struct ipahal_stats_get_offset_quota {
+ struct ipahal_stats_init_quota init;
+};
+
+/*
+ * struct ipahal_stats_quota - Quota statistics
+ * @num_ipv4_bytes: IPv4 bytes
+ * @num_ipv6_bytes: IPv6 bytes
+ * @num_ipv4_pkts: IPv4 packets
+ * @num_ipv6_pkts: IPv6 packets
+ */
+struct ipahal_stats_quota {
+ u64 num_ipv4_bytes;
+ u64 num_ipv6_bytes;
+ u64 num_ipv4_pkts;
+ u64 num_ipv6_pkts;
+};
+
+/*
+ * struct ipahal_stats_quota_all - Quota statistics for all pipes
+ * @stats: array of statistics per pipe
+ */
+struct ipahal_stats_quota_all {
+ struct ipahal_stats_quota stats[IPAHAL_MAX_PIPES];
+};
+
+/*
+ * struct ipahal_stats_init_tethering - Initializations parameters for tethering
+ * @prod_bitmask: bit mask of producer pipes to be monitored
+ * @cons_bitmask: bit mask of consumer pipes to be monitored per producer
+ */
+struct ipahal_stats_init_tethering {
+ u32 prod_bitmask;
+ u32 cons_bitmask[IPAHAL_MAX_PIPES];
+};
+
+/*
+ * struct ipahal_stats_get_offset_tethering - Get offset parameters for
+ * tethering
+ * @init: initialization parameters used in initialization of stats
+ */
+struct ipahal_stats_get_offset_tethering {
+ struct ipahal_stats_init_tethering init;
+};
+
+/*
+ * struct ipahal_stats_tethering - Tethering statistics
+ * @num_ipv4_bytes: IPv4 bytes
+ * @num_ipv6_bytes: IPv6 bytes
+ * @num_ipv4_pkts: IPv4 packets
+ * @num_ipv6_pkts: IPv6 packets
+ */
+struct ipahal_stats_tethering {
+ u64 num_ipv4_bytes;
+ u64 num_ipv6_bytes;
+ u64 num_ipv4_pkts;
+ u64 num_ipv6_pkts;
+};
+
+/*
+ * struct ipahal_stats_tethering_all - Tethering statistics for all pipes
+ * @stats: matrix of statistics per pair of pipes
+ */
+struct ipahal_stats_tethering_all {
+ struct ipahal_stats_tethering
+ stats[IPAHAL_MAX_PIPES][IPAHAL_MAX_PIPES];
+};
+
+/*
+ * struct ipahal_stats_init_flt_rt - Initializations parameters for flt_rt
+ * @rule_id_bitmask: array describes which rule ids to monitor.
+ * rule_id bit is determined by:
+ * index to the array => rule_id / 32
+ * bit to enable => rule_id % 32
+ */
+struct ipahal_stats_init_flt_rt {
+ u32 rule_id_bitmask[IPAHAL_MAX_RULE_ID_32];
+};
+
+/*
+ * struct ipahal_stats_get_offset_flt_rt - Get offset parameters for flt_rt
+ * @init: initialization parameters used in initialization of stats
+ * @rule_id: rule_id to get the offset for
+ */
+struct ipahal_stats_get_offset_flt_rt {
+ struct ipahal_stats_init_flt_rt init;
+ u32 rule_id;
+};
+
+/*
+ * struct ipahal_stats_flt_rt - flt_rt statistics
+ * @num_packets: Total number of packets hit this rule
+ * @num_packets_hash: Total number of packets hit this rule in hash table
+ */
+struct ipahal_stats_flt_rt {
+ u32 num_packets;
+ u32 num_packets_hash;
+};
+
+/*
+ * struct ipahal_stats_init_drop - Initializations parameters for Drop
+ * @enabled_bitmask: bit mask of pipes to be monitored
+ */
+struct ipahal_stats_init_drop {
+ u32 enabled_bitmask;
+};
+
+/*
+ * struct ipahal_stats_get_offset_drop - Get offset parameters for Drop
+ * @init: initialization parameters used in initialization of stats
+ */
+struct ipahal_stats_get_offset_drop {
+ struct ipahal_stats_init_drop init;
+};
+
+/*
+ * struct ipahal_stats_drop - Packet Drop statistics
+ * @drop_packet_cnt: number of packets dropped
+ * @drop_byte_cnt: number of bytes dropped
+ */
+struct ipahal_stats_drop {
+ u32 drop_packet_cnt;
+ u32 drop_byte_cnt;
+};
+
+/*
+ * struct ipahal_stats_drop_all - Drop statistics for all pipes
+ * @stats: array of statistics per pipes
+ */
+struct ipahal_stats_drop_all {
+ struct ipahal_stats_drop stats[IPAHAL_MAX_PIPES];
+};
+
+/*
+ * ipahal_stats_generate_init_pyld - Generate the init payload for stats
+ * @type: type of stats
+ * @params: init_pyld parameters based of stats type
+ * @is_atomic_ctx: is calling context atomic ?
+ *
+ * This function will generate the initialization payload for a particular
+ * statistic in hardware. IPA driver is expected to use this payload to
+ * initialize the SRAM.
+ *
+ * Return: pointer to ipahal_stats_init_pyld on success or NULL on failure.
+ */
+struct ipahal_stats_init_pyld *ipahal_stats_generate_init_pyld(
+ enum ipahal_hw_stats_type type, void *params, bool is_atomic_ctx);
+
+/*
+ * ipahal_destroy_stats_init_pyld() - Destroy/Release bulk that was built
+ * by the ipahal_stats_generate_init_pyld function.
+ */
+static inline void ipahal_destroy_stats_init_pyld(
+ struct ipahal_stats_init_pyld *pyld)
+{
+ kfree(pyld);
+}
+
+/*
+ * ipahal_stats_get_offset - Get the offset / size of payload for stats
+ * @type: type of stats
+ * @params: get_offset parameters based of stats type
+ * @out: out parameter for the offset and size.
+ *
+ * This function will return the offset of the counter from beginning of
+ * the table.IPA driver is expected to read this portion in SRAM and pass
+ * it to ipahal_parse_stats() to interprete the stats.
+ *
+ * Return: 0 on success and negative on failure
+ */
+int ipahal_stats_get_offset(enum ipahal_hw_stats_type type, void *params,
+ struct ipahal_stats_offset *out);
+
+/*
+ * ipahal_parse_stats - parse statistics
+ * @type: type of stats
+ * @init_params: init_pyld parameters used on init
+ * @raw_stats: stats read from IPA SRAM
+ * @parsed_stats: pointer to parsed stats based on type
+ *
+ * Return: 0 on success and negative on failure
+ */
+int ipahal_parse_stats(enum ipahal_hw_stats_type type, void *init_params,
+ void *raw_stats, void *parsed_stats);
+
+
+#endif /* _IPAHAL_HW_STATS_H_ */
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_hw_stats_i.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_hw_stats_i.h
new file mode 100644
index 0000000..3bb761d
--- /dev/null
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_hw_stats_i.h
@@ -0,0 +1,55 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _IPAHAL_HW_STATS_I_H_
+#define _IPAHAL_HW_STATS_I_H_
+
+#include "ipahal_hw_stats.h"
+
+int ipahal_hw_stats_init(enum ipa_hw_type ipa_hw_type);
+
+struct ipahal_stats_quota_hw {
+ u64 num_ipv4_bytes;
+ u64 num_ipv4_pkts:32;
+ u64 num_ipv6_pkts:32;
+ u64 num_ipv6_bytes;
+};
+
+struct ipahal_stats_tethering_hdr_hw {
+ u64 dst_mask:32;
+ u64 offset:32;
+};
+
+struct ipahal_stats_tethering_hw {
+ u64 num_ipv4_bytes;
+ u64 num_ipv4_pkts:32;
+ u64 num_ipv6_pkts:32;
+ u64 num_ipv6_bytes;
+};
+
+struct ipahal_stats_flt_rt_hdr_hw {
+ u64 en_mask:32;
+ u64 reserved:16;
+ u64 cnt_offset:16;
+};
+
+struct ipahal_stats_flt_rt_hw {
+ u64 num_packets_hash:32;
+ u64 num_packets:32;
+};
+
+struct ipahal_stats_drop_hw {
+ u64 drop_byte_cnt:40;
+ u64 drop_packet_cnt:24;
+};
+
+#endif /* _IPAHAL_HW_STATS_I_H_ */
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_i.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_i.h
index 1c4b287..5eb1aef 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_i.h
@@ -46,6 +46,9 @@
IPAHAL_DRV_NAME " %s:%d " fmt, ## args); \
} while (0)
+#define IPAHAL_MEM_ALLOC(__size, __is_atomic_ctx) \
+ (kzalloc((__size), ((__is_atomic_ctx) ? GFP_ATOMIC : GFP_KERNEL)))
+
/*
* struct ipahal_context - HAL global context data
* @hw_type: IPA H/W type/version.
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c
index 0dccb5b..dc71414 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c
@@ -87,6 +87,24 @@
__stringify(IPA_DPS_SEQUENCER_FIRST),
__stringify(IPA_HPS_SEQUENCER_FIRST),
__stringify(IPA_CLKON_CFG),
+ __stringify(IPA_STAT_QUOTA_BASE_n),
+ __stringify(IPA_STAT_QUOTA_MASK_n),
+ __stringify(IPA_STAT_TETHERING_BASE_n),
+ __stringify(IPA_STAT_TETHERING_MASK_n),
+ __stringify(IPA_STAT_FILTER_IPV4_BASE),
+ __stringify(IPA_STAT_FILTER_IPV6_BASE),
+ __stringify(IPA_STAT_ROUTER_IPV4_BASE),
+ __stringify(IPA_STAT_ROUTER_IPV6_BASE),
+ __stringify(IPA_STAT_FILTER_IPV4_START_ID),
+ __stringify(IPA_STAT_FILTER_IPV6_START_ID),
+ __stringify(IPA_STAT_ROUTER_IPV4_START_ID),
+ __stringify(IPA_STAT_ROUTER_IPV6_START_ID),
+ __stringify(IPA_STAT_FILTER_IPV4_END_ID),
+ __stringify(IPA_STAT_FILTER_IPV6_END_ID),
+ __stringify(IPA_STAT_ROUTER_IPV4_END_ID),
+ __stringify(IPA_STAT_ROUTER_IPV6_END_ID),
+ __stringify(IPA_STAT_DROP_CNT_BASE_n),
+ __stringify(IPA_STAT_DROP_CNT_MASK_n),
};
static void ipareg_construct_dummy(enum ipahal_reg_name reg,
@@ -1510,6 +1528,60 @@
ipareg_construct_endp_init_conn_track_n,
ipareg_parse_dummy,
0x00000850, 0x70},
+ [IPA_HW_v4_0][IPA_STAT_QUOTA_BASE_n] = {
+ ipareg_construct_dummy, ipareg_parse_dummy,
+ 0x00000700, 0x4 },
+ [IPA_HW_v4_0][IPA_STAT_QUOTA_MASK_n] = {
+ ipareg_construct_dummy, ipareg_parse_dummy,
+ 0x00000708, 0x4 },
+ [IPA_HW_v4_0][IPA_STAT_TETHERING_BASE_n] = {
+ ipareg_construct_dummy, ipareg_parse_dummy,
+ 0x00000710, 0x4 },
+ [IPA_HW_v4_0][IPA_STAT_TETHERING_MASK_n] = {
+ ipareg_construct_dummy, ipareg_parse_dummy,
+ 0x00000718, 0x4 },
+ [IPA_HW_v4_0][IPA_STAT_FILTER_IPV4_BASE] = {
+ ipareg_construct_dummy, ipareg_parse_dummy,
+ 0x00000720, 0x0 },
+ [IPA_HW_v4_0][IPA_STAT_FILTER_IPV6_BASE] = {
+ ipareg_construct_dummy, ipareg_parse_dummy,
+ 0x00000724, 0x0 },
+ [IPA_HW_v4_0][IPA_STAT_ROUTER_IPV4_BASE] = {
+ ipareg_construct_dummy, ipareg_parse_dummy,
+ 0x00000728, 0x0 },
+ [IPA_HW_v4_0][IPA_STAT_ROUTER_IPV6_BASE] = {
+ ipareg_construct_dummy, ipareg_parse_dummy,
+ 0x0000072C, 0x0 },
+ [IPA_HW_v4_0][IPA_STAT_FILTER_IPV4_START_ID] = {
+ ipareg_construct_dummy, ipareg_parse_dummy,
+ 0x00000730, 0x0 },
+ [IPA_HW_v4_0][IPA_STAT_FILTER_IPV6_START_ID] = {
+ ipareg_construct_dummy, ipareg_parse_dummy,
+ 0x00000734, 0x0 },
+ [IPA_HW_v4_0][IPA_STAT_ROUTER_IPV4_START_ID] = {
+ ipareg_construct_dummy, ipareg_parse_dummy,
+ 0x00000738, 0x0 },
+ [IPA_HW_v4_0][IPA_STAT_ROUTER_IPV6_START_ID] = {
+ ipareg_construct_dummy, ipareg_parse_dummy,
+ 0x0000073C, 0x0 },
+ [IPA_HW_v4_0][IPA_STAT_FILTER_IPV4_END_ID] = {
+ ipareg_construct_dummy, ipareg_parse_dummy,
+ 0x00000740, 0x0 },
+ [IPA_HW_v4_0][IPA_STAT_FILTER_IPV6_END_ID] = {
+ ipareg_construct_dummy, ipareg_parse_dummy,
+ 0x00000744, 0x0 },
+ [IPA_HW_v4_0][IPA_STAT_ROUTER_IPV4_END_ID] = {
+ ipareg_construct_dummy, ipareg_parse_dummy,
+ 0x00000748, 0x0 },
+ [IPA_HW_v4_0][IPA_STAT_ROUTER_IPV6_END_ID] = {
+ ipareg_construct_dummy, ipareg_parse_dummy,
+ 0x0000074C, 0x0 },
+ [IPA_HW_v4_0][IPA_STAT_DROP_CNT_BASE_n] = {
+ ipareg_construct_dummy, ipareg_parse_dummy,
+ 0x00000750, 0x4 },
+ [IPA_HW_v4_0][IPA_STAT_DROP_CNT_MASK_n] = {
+ ipareg_construct_dummy, ipareg_parse_dummy,
+ 0x00000758, 0x4 },
};
/*
@@ -1853,6 +1925,11 @@
IPA_AGGR_FORCE_CLOSE_AGGR_FORCE_CLOSE_PIPE_BITMAP_BMSK_V4_0;
}
+ if (ep_idx > (sizeof(valmask->val) * 8 - 1)) {
+ IPAHAL_ERR("too big ep_idx %d\n", ep_idx);
+ ipa_assert();
+ return;
+ }
IPA_SETFIELD_IN_REG(valmask->val, 1 << ep_idx, shft, bmsk);
valmask->mask = bmsk << shft;
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h
index 3df49ce..a2864cd 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h
@@ -90,6 +90,24 @@
IPA_DPS_SEQUENCER_FIRST,
IPA_HPS_SEQUENCER_FIRST,
IPA_CLKON_CFG,
+ IPA_STAT_QUOTA_BASE_n,
+ IPA_STAT_QUOTA_MASK_n,
+ IPA_STAT_TETHERING_BASE_n,
+ IPA_STAT_TETHERING_MASK_n,
+ IPA_STAT_FILTER_IPV4_BASE,
+ IPA_STAT_FILTER_IPV6_BASE,
+ IPA_STAT_ROUTER_IPV4_BASE,
+ IPA_STAT_ROUTER_IPV6_BASE,
+ IPA_STAT_FILTER_IPV4_START_ID,
+ IPA_STAT_FILTER_IPV6_START_ID,
+ IPA_STAT_ROUTER_IPV4_START_ID,
+ IPA_STAT_ROUTER_IPV6_START_ID,
+ IPA_STAT_FILTER_IPV4_END_ID,
+ IPA_STAT_FILTER_IPV6_END_ID,
+ IPA_STAT_ROUTER_IPV4_END_ID,
+ IPA_STAT_ROUTER_IPV6_END_ID,
+ IPA_STAT_DROP_CNT_BASE_n,
+ IPA_STAT_DROP_CNT_MASK_n,
IPA_REG_MAX,
};
diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
index b19c71a..b119a69 100644
--- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
@@ -702,6 +702,11 @@
/* send ipa_fltr_installed_notif_req_msg_v01 to Q6*/
req->source_pipe_index =
ipa3_get_ep_mapping(IPA_CLIENT_APPS_WAN_PROD);
+ if (req->source_pipe_index == IPA_EP_NOT_ALLOCATED) {
+ IPAWANERR("ep mapping failed\n");
+ retval = -EFAULT;
+ }
+
req->install_status = QMI_RESULT_SUCCESS_V01;
req->rule_id_valid = 1;
req->rule_id_len = rmnet_ipa3_ctx->num_q6_rules;
@@ -1927,7 +1932,9 @@
if (ret < 0)
IPAWANERR("Error deleting resource %d, ret=%d\n",
IPA_RM_RESOURCE_Q6_PROD, ret);
- destroy_workqueue(rmnet_ipa3_ctx->rm_q6_wq);
+
+ if (rmnet_ipa3_ctx->rm_q6_wq)
+ destroy_workqueue(rmnet_ipa3_ctx->rm_q6_wq);
}
static void ipa3_wake_tx_queue(struct work_struct *work)
@@ -2267,7 +2274,10 @@
IPAWANERR("Error deleting resource %d, ret=%d\n",
IPA_RM_RESOURCE_WWAN_0_PROD, ret);
create_rsrc_err:
- ipa3_q6_deinitialize_rm();
+
+ if (!atomic_read(&rmnet_ipa3_ctx->is_ssr))
+ ipa3_q6_deinitialize_rm();
+
q6_init_err:
free_netdev(dev);
rmnet_ipa3_ctx->wwan_priv = NULL;
diff --git a/drivers/platform/msm/ipa/test/Makefile b/drivers/platform/msm/ipa/test/Makefile
index c20fd2b..af46bf2 100644
--- a/drivers/platform/msm/ipa/test/Makefile
+++ b/drivers/platform/msm/ipa/test/Makefile
@@ -1,2 +1,2 @@
obj-$(CONFIG_IPA_UT) += ipa_ut_mod.o
-ipa_ut_mod-y := ipa_ut_framework.o ipa_test_example.o ipa_test_mhi.o ipa_test_dma.o
+ipa_ut_mod-y := ipa_ut_framework.o ipa_test_example.o ipa_test_mhi.o ipa_test_dma.o ipa_test_hw_stats.o
diff --git a/drivers/platform/msm/ipa/test/ipa_test_hw_stats.c b/drivers/platform/msm/ipa/test/ipa_test_hw_stats.c
new file mode 100644
index 0000000..d37920e
--- /dev/null
+++ b/drivers/platform/msm/ipa/test/ipa_test_hw_stats.c
@@ -0,0 +1,330 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "ipa_ut_framework.h"
+#include <linux/netdevice.h>
+
+struct ipa_test_hw_stats_ctx {
+ u32 odu_prod_hdl;
+ u32 odu_cons_hdl;
+ u32 rt4_usb;
+ u32 rt6_usb;
+ u32 rt4_odu_cons;
+ u32 rt6_odu_cons;
+ atomic_t odu_pending;
+};
+
+static struct ipa_test_hw_stats_ctx *ctx;
+
+static int ipa_test_hw_stats_suite_setup(void **ppriv)
+{
+ IPA_UT_DBG("Start Setup\n");
+
+ if (!ctx)
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+
+ return 0;
+}
+
+static int ipa_test_hw_stats_suite_teardown(void *priv)
+{
+ IPA_UT_DBG("Start Teardown\n");
+
+ return 0;
+}
+
+static void odu_prod_notify(void *priv, enum ipa_dp_evt_type evt,
+ unsigned long data)
+{
+ struct sk_buff *skb = (struct sk_buff *)data;
+
+ switch (evt) {
+ case IPA_RECEIVE:
+ dev_kfree_skb_any(skb);
+ break;
+ case IPA_WRITE_DONE:
+ atomic_dec(&ctx->odu_pending);
+ dev_kfree_skb_any(skb);
+ break;
+ default:
+ IPA_UT_ERR("unexpected evt %d\n", evt);
+ }
+}
+static void odu_cons_notify(void *priv, enum ipa_dp_evt_type evt,
+ unsigned long data)
+{
+ struct sk_buff *skb = (struct sk_buff *)data;
+ int ret;
+
+ switch (evt) {
+ case IPA_RECEIVE:
+ if (atomic_read(&ctx->odu_pending) >= 64)
+ msleep(20);
+ atomic_inc(&ctx->odu_pending);
+ skb_put(skb, 100);
+ ret = ipa_tx_dp(IPA_CLIENT_ODU_PROD, skb, NULL);
+ while (ret) {
+ msleep(100);
+ ret = ipa_tx_dp(IPA_CLIENT_ODU_PROD, skb, NULL);
+ }
+ break;
+ case IPA_WRITE_DONE:
+ dev_kfree_skb_any(skb);
+ break;
+ default:
+ IPA_UT_ERR("unexpected evt %d\n", evt);
+ }
+}
+
+static int ipa_test_hw_stats_configure(void *priv)
+{
+ struct ipa_sys_connect_params odu_prod_params;
+ struct ipa_sys_connect_params odu_emb_cons_params;
+ int res;
+
+ /* first connect all additional pipe */
+ memset(&odu_prod_params, 0, sizeof(odu_prod_params));
+ memset(&odu_emb_cons_params, 0, sizeof(odu_emb_cons_params));
+
+ odu_prod_params.client = IPA_CLIENT_ODU_PROD;
+ odu_prod_params.desc_fifo_sz = 0x1000;
+ odu_prod_params.priv = NULL;
+ odu_prod_params.notify = odu_prod_notify;
+ res = ipa_setup_sys_pipe(&odu_prod_params,
+ &ctx->odu_prod_hdl);
+ if (res) {
+ IPA_UT_ERR("fail to setup sys pipe ODU_PROD %d\n", res);
+ return res;
+ }
+
+ odu_emb_cons_params.client = IPA_CLIENT_ODU_EMB_CONS;
+ odu_emb_cons_params.desc_fifo_sz = 0x1000;
+ odu_emb_cons_params.priv = NULL;
+ odu_emb_cons_params.notify = odu_cons_notify;
+ res = ipa_setup_sys_pipe(&odu_emb_cons_params,
+ &ctx->odu_cons_hdl);
+ if (res) {
+ IPA_UT_ERR("fail to setup sys pipe ODU_EMB_CONS %d\n", res);
+ ipa_teardown_sys_pipe(ctx->odu_prod_hdl);
+ return res;
+ }
+
+ IPA_UT_INFO("Configured. Please connect USB RNDIS now\n");
+
+ return 0;
+}
+
+static int ipa_test_hw_stats_add_FnR(void *priv)
+{
+ struct ipa_ioc_add_rt_rule *rt_rule;
+ struct ipa_ioc_add_flt_rule *flt_rule;
+ struct ipa_ioc_get_rt_tbl rt_lookup;
+ int ret;
+
+ rt_rule = kzalloc(sizeof(*rt_rule) + 1 * sizeof(struct ipa_rt_rule_add),
+ GFP_KERNEL);
+ if (!rt_rule) {
+ IPA_UT_DBG("no mem\n");
+ return -ENOMEM;
+ }
+
+ flt_rule = kzalloc(sizeof(*flt_rule) +
+ 1 * sizeof(struct ipa_flt_rule_add), GFP_KERNEL);
+ if (!flt_rule) {
+ IPA_UT_DBG("no mem\n");
+ ret = -ENOMEM;
+ goto free_rt;
+ }
+
+ rt_rule->commit = 1;
+ rt_rule->ip = IPA_IP_v4;
+ rt_lookup.ip = rt_rule->ip;
+ strlcpy(rt_rule->rt_tbl_name, "V4_RT_TO_USB_CONS",
+ IPA_RESOURCE_NAME_MAX);
+ strlcpy(rt_lookup.name, rt_rule->rt_tbl_name, IPA_RESOURCE_NAME_MAX);
+ rt_rule->num_rules = 1;
+ rt_rule->rules[0].rule.dst = IPA_CLIENT_USB_CONS;
+ rt_rule->rules[0].rule.attrib.attrib_mask = IPA_FLT_DST_PORT;
+ rt_rule->rules[0].rule.attrib.dst_port = 5002;
+ rt_rule->rules[0].rule.hashable = true;
+ if (ipa_add_rt_rule(rt_rule) || rt_rule->rules[0].status) {
+ IPA_UT_ERR("failed to install V4 rules\n");
+ ret = -EFAULT;
+ goto free_flt;
+ }
+ if (ipa_get_rt_tbl(&rt_lookup)) {
+ IPA_UT_ERR("failed to query V4 rules\n");
+ ret = -EFAULT;
+ goto free_flt;
+ }
+ ctx->rt4_usb = rt_lookup.hdl;
+
+ memset(rt_rule, 0, sizeof(*rt_rule));
+ rt_rule->commit = 1;
+ rt_rule->ip = IPA_IP_v6;
+ rt_lookup.ip = rt_rule->ip;
+ strlcpy(rt_rule->rt_tbl_name, "V6_RT_TO_USB_CONS",
+ IPA_RESOURCE_NAME_MAX);
+ strlcpy(rt_lookup.name, rt_rule->rt_tbl_name, IPA_RESOURCE_NAME_MAX);
+ rt_rule->num_rules = 1;
+ rt_rule->rules[0].rule.dst = IPA_CLIENT_USB_CONS;
+ rt_rule->rules[0].rule.attrib.attrib_mask = IPA_FLT_DST_PORT;
+ rt_rule->rules[0].rule.attrib.dst_port = 5002;
+ rt_rule->rules[0].rule.hashable = true;
+ if (ipa_add_rt_rule(rt_rule) || rt_rule->rules[0].status) {
+ IPA_UT_ERR("failed to install V4 rules\n");
+ ret = -EFAULT;
+ goto free_flt;
+ }
+ if (ipa_get_rt_tbl(&rt_lookup)) {
+ IPA_UT_ERR("failed to query V4 rules\n");
+ ret = -EFAULT;
+ goto free_flt;
+ }
+ ctx->rt6_usb = rt_lookup.hdl;
+
+ memset(rt_rule, 0, sizeof(*rt_rule));
+ rt_rule->commit = 1;
+ rt_rule->ip = IPA_IP_v4;
+ rt_lookup.ip = rt_rule->ip;
+ strlcpy(rt_rule->rt_tbl_name, "V4_RT_TO_ODU_CONS",
+ IPA_RESOURCE_NAME_MAX);
+ strlcpy(rt_lookup.name, rt_rule->rt_tbl_name, IPA_RESOURCE_NAME_MAX);
+ rt_rule->num_rules = 1;
+ rt_rule->rules[0].rule.dst = IPA_CLIENT_ODU_EMB_CONS;
+ rt_rule->rules[0].rule.attrib.attrib_mask = IPA_FLT_DST_PORT;
+ rt_rule->rules[0].rule.attrib.dst_port = 5002;
+ rt_rule->rules[0].rule.hashable = true;
+ if (ipa_add_rt_rule(rt_rule) || rt_rule->rules[0].status) {
+ IPA_UT_ERR("failed to install V4 rules\n");
+ ret = -EFAULT;
+ goto free_flt;
+ }
+ if (ipa_get_rt_tbl(&rt_lookup)) {
+ IPA_UT_ERR("failed to query V4 rules\n");
+ return -EFAULT;
+ }
+ ctx->rt4_odu_cons = rt_lookup.hdl;
+
+ memset(rt_rule, 0, sizeof(*rt_rule));
+ rt_rule->commit = 1;
+ rt_rule->ip = IPA_IP_v6;
+ rt_lookup.ip = rt_rule->ip;
+ strlcpy(rt_rule->rt_tbl_name, "V6_RT_TO_ODU_CONS",
+ IPA_RESOURCE_NAME_MAX);
+ strlcpy(rt_lookup.name, rt_rule->rt_tbl_name, IPA_RESOURCE_NAME_MAX);
+ rt_rule->num_rules = 1;
+ rt_rule->rules[0].rule.dst = IPA_CLIENT_ODU_EMB_CONS;
+ rt_rule->rules[0].rule.attrib.attrib_mask = IPA_FLT_DST_PORT;
+ rt_rule->rules[0].rule.attrib.dst_port = 5002;
+ rt_rule->rules[0].rule.hashable = true;
+ if (ipa_add_rt_rule(rt_rule) || rt_rule->rules[0].status) {
+ IPA_UT_ERR("failed to install V4 rules\n");
+ ret = -EFAULT;
+ goto free_flt;
+ }
+ if (ipa_get_rt_tbl(&rt_lookup)) {
+ IPA_UT_ERR("failed to query V4 rules\n");
+ ret = -EFAULT;
+ goto free_flt;
+ }
+ ctx->rt6_odu_cons = rt_lookup.hdl;
+
+ flt_rule->commit = 1;
+ flt_rule->ip = IPA_IP_v4;
+ flt_rule->ep = IPA_CLIENT_USB_PROD;
+ flt_rule->num_rules = 1;
+ flt_rule->rules[0].at_rear = 1;
+ flt_rule->rules[0].rule.action = IPA_PASS_TO_ROUTING;
+ flt_rule->rules[0].rule.attrib.attrib_mask = IPA_FLT_DST_PORT;
+ flt_rule->rules[0].rule.attrib.dst_port = 5002;
+ flt_rule->rules[0].rule.rt_tbl_hdl = ctx->rt4_odu_cons;
+ flt_rule->rules[0].rule.hashable = 1;
+ if (ipa_add_flt_rule(flt_rule) || flt_rule->rules[0].status) {
+ IPA_UT_ERR("failed to install V4 rules\n");
+ ret = -EFAULT;
+ goto free_flt;
+ }
+
+ memset(flt_rule, 0, sizeof(*flt_rule));
+ flt_rule->commit = 1;
+ flt_rule->ip = IPA_IP_v6;
+ flt_rule->ep = IPA_CLIENT_USB_PROD;
+ flt_rule->num_rules = 1;
+ flt_rule->rules[0].at_rear = 1;
+ flt_rule->rules[0].rule.action = IPA_PASS_TO_ROUTING;
+ flt_rule->rules[0].rule.attrib.attrib_mask = IPA_FLT_DST_PORT;
+ flt_rule->rules[0].rule.attrib.dst_port = 5002;
+ flt_rule->rules[0].rule.rt_tbl_hdl = ctx->rt6_odu_cons;
+ flt_rule->rules[0].rule.hashable = 1;
+ if (ipa_add_flt_rule(flt_rule) || flt_rule->rules[0].status) {
+ IPA_UT_ERR("failed to install V6 rules\n");
+ ret = -EFAULT;
+ goto free_flt;
+ }
+
+ memset(flt_rule, 0, sizeof(*flt_rule));
+ flt_rule->commit = 1;
+ flt_rule->ip = IPA_IP_v4;
+ flt_rule->ep = IPA_CLIENT_ODU_PROD;
+ flt_rule->num_rules = 1;
+ flt_rule->rules[0].at_rear = 1;
+ flt_rule->rules[0].rule.action = IPA_PASS_TO_ROUTING;
+ flt_rule->rules[0].rule.attrib.attrib_mask = IPA_FLT_DST_PORT;
+ flt_rule->rules[0].rule.attrib.dst_port = 5002;
+ flt_rule->rules[0].rule.rt_tbl_hdl = ctx->rt4_usb;
+ flt_rule->rules[0].rule.hashable = 1;
+ if (ipa_add_flt_rule(flt_rule) || flt_rule->rules[0].status) {
+ IPA_UT_ERR("failed to install V4 rules\n");
+ ret = -EFAULT;
+ goto free_flt;
+ }
+
+ memset(flt_rule, 0, sizeof(*flt_rule));
+ flt_rule->commit = 1;
+ flt_rule->ip = IPA_IP_v6;
+ flt_rule->ep = IPA_CLIENT_ODU_PROD;
+ flt_rule->num_rules = 1;
+ flt_rule->rules[0].at_rear = 1;
+ flt_rule->rules[0].rule.action = IPA_PASS_TO_ROUTING;
+ flt_rule->rules[0].rule.attrib.attrib_mask = IPA_FLT_DST_PORT;
+ flt_rule->rules[0].rule.attrib.dst_port = 5002;
+ flt_rule->rules[0].rule.rt_tbl_hdl = ctx->rt6_usb;
+ flt_rule->rules[0].rule.hashable = 1;
+ if (ipa_add_flt_rule(flt_rule) || flt_rule->rules[0].status) {
+ IPA_UT_ERR("failed to install V6 rules\n");
+ ret = -EFAULT;
+ goto free_flt;
+ }
+
+ IPA_UT_INFO(
+ "Rules added. Please start data transfer on ports 5001/5002\n");
+ ret = 0;
+free_flt:
+ kfree(flt_rule);
+free_rt:
+ kfree(rt_rule);
+ return ret;
+
+}
+
+/* Suite definition block */
+IPA_UT_DEFINE_SUITE_START(hw_stats, "HW stats test",
+ ipa_test_hw_stats_suite_setup, ipa_test_hw_stats_suite_teardown)
+{
+ IPA_UT_ADD_TEST(configure, "Configure the setup",
+ ipa_test_hw_stats_configure, false, IPA_HW_v4_0, IPA_HW_MAX),
+
+ IPA_UT_ADD_TEST(add_rules, "Add FLT and RT rules",
+ ipa_test_hw_stats_add_FnR, false, IPA_HW_v4_0, IPA_HW_MAX),
+
+} IPA_UT_DEFINE_SUITE_END(hw_stats);
diff --git a/drivers/platform/msm/ipa/test/ipa_ut_suite_list.h b/drivers/platform/msm/ipa/test/ipa_ut_suite_list.h
index 4a9d3b0..823edcf 100644
--- a/drivers/platform/msm/ipa/test/ipa_ut_suite_list.h
+++ b/drivers/platform/msm/ipa/test/ipa_ut_suite_list.h
@@ -23,6 +23,7 @@
IPA_UT_DECLARE_SUITE(mhi);
IPA_UT_DECLARE_SUITE(dma);
IPA_UT_DECLARE_SUITE(example);
+IPA_UT_DECLARE_SUITE(hw_stats);
/**
@@ -34,6 +35,7 @@
IPA_UT_REGISTER_SUITE(mhi),
IPA_UT_REGISTER_SUITE(dma),
IPA_UT_REGISTER_SUITE(example),
+ IPA_UT_REGISTER_SUITE(hw_stats),
} IPA_UT_DEFINE_ALL_SUITES_END;
#endif /* _IPA_UT_SUITE_LIST_H_ */
diff --git a/drivers/power/supply/qcom/pmic-voter.c b/drivers/power/supply/qcom/pmic-voter.c
index 10a1c54..d616dd8 100644
--- a/drivers/power/supply/qcom/pmic-voter.c
+++ b/drivers/power/supply/qcom/pmic-voter.c
@@ -438,12 +438,14 @@
int rerun_election(struct votable *votable)
{
int rc = 0;
+ int effective_result;
lock_votable(votable);
+ effective_result = get_effective_result_locked(votable);
if (votable->callback)
rc = votable->callback(votable,
- votable->data,
- votable->effective_result,
+ votable->data,
+ effective_result,
get_client_str(votable, votable->effective_client_id));
unlock_votable(votable);
return rc;
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index c78bb9e..a43c18f 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -7864,7 +7864,7 @@
__func__);
pm_runtime_get_sync(hba->dev);
ufshcd_detect_device(hba);
- pm_runtime_put_sync(hba->dev);
+ /* ufshcd_probe_hba() calls pm_runtime_put_sync() on exit */
} else {
dev_dbg(hba->dev, "%s: card removed notification received\n",
__func__);
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 5be06ba..38eff96 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -752,3 +752,10 @@
to Alway On processor using QMP transport.
source "drivers/soc/qcom/memshare/Kconfig"
+
+config QSEE_IPC_IRQ_BRIDGE
+ tristate "QSEE IPC Interrupt Bridge"
+ help
+ This module enables bridging an Inter-Processor Communication(IPC)
+ interrupt from a remote subsystem directed towards Qualcomm
+ Technologies, Inc. Secure Execution Environment(QSEE).
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 9736cdc..2d7d62a 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -79,3 +79,4 @@
obj-$(CONFIG_QTI_RPM_STATS_LOG) += rpm_stats.o
obj-$(CONFIG_QCOM_SMCINVOKE) += smcinvoke.o
obj-$(CONFIG_QMP_DEBUGFS_CLIENT) += qmp-debugfs-client.o
+obj-$(CONFIG_QSEE_IPC_IRQ_BRIDGE) += qsee_ipc_irq_bridge.o
diff --git a/drivers/soc/qcom/msm_performance.c b/drivers/soc/qcom/msm_performance.c
index 25e6a9d..979c628 100644
--- a/drivers/soc/qcom/msm_performance.c
+++ b/drivers/soc/qcom/msm_performance.c
@@ -25,6 +25,7 @@
#include <linux/module.h>
#include <linux/input.h>
#include <linux/kthread.h>
+#include <soc/qcom/msm-core.h>
static struct mutex managed_cpus_lock;
diff --git a/drivers/soc/qcom/qsee_ipc_irq_bridge.c b/drivers/soc/qcom/qsee_ipc_irq_bridge.c
new file mode 100644
index 0000000..ac3dcc3
--- /dev/null
+++ b/drivers/soc/qcom/qsee_ipc_irq_bridge.c
@@ -0,0 +1,624 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/cdev.h>
+#include <linux/interrupt.h>
+#include <linux/ipc_logging.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <soc/qcom/subsystem_notif.h>
+#include <soc/qcom/subsystem_restart.h>
+
+#define MODULE_NAME "qsee_ipc_irq_bridge"
+#define DEVICE_NAME MODULE_NAME
+#define NUM_LOG_PAGES 4
+
+#define QIIB_DBG(x...) do { \
+ if (qiib_info->log_ctx) \
+ ipc_log_string(qiib_info->log_ctx, x); \
+ else \
+ pr_debug(x); \
+ } while (0)
+
+#define QIIB_ERR(x...) do { \
+ pr_err(x); \
+ if (qiib_info->log_ctx) \
+ ipc_log_string(qiib_info->log_ctx, x); \
+ } while (0)
+
+static void qiib_cleanup(void);
+
+/**
+ * qiib_dev - QSEE IPC IRQ bridge device
+ * @dev_list: qiib device list.
+ * @i: Index to this character device.
+ * @dev_name: Device node name used by the clients.
+ * @cdev: structure to the internal character device.
+ * @devicep: Pointer to the qiib class device structure.
+ * @poll_wait_queue: poll thread wait queue.
+ * @irq_num: IRQ number usd for this device.
+ * @rx_irq_reset_reg: Reference to the register to reset the rx irq
+ * line, if applicable.
+ * @irq_mask: Mask written to @rx_irq_reset_reg to clear the irq.
+ * @irq_pending_count: The number of IRQs pending.
+ * @irq_pending_count_lock: Lock to protect @irq_pending_cont.
+ * @ssr_name: Name of the subsystem recognized by the SSR framework.
+ * @nb: SSR Notifier callback.
+ * @notifier_handle: SSR Notifier handle.
+ * @in_reset: Flag to check the SSR state.
+ */
+struct qiib_dev {
+ struct list_head dev_list;
+ uint32_t i;
+
+ const char *dev_name;
+ struct cdev cdev;
+ struct device *devicep;
+
+ wait_queue_head_t poll_wait_queue;
+
+ uint32_t irq_line;
+ void __iomem *rx_irq_reset_reg;
+ uint32_t irq_mask;
+ uint32_t irq_pending_count;
+ spinlock_t irq_pending_count_lock;
+
+ const char *ssr_name;
+ struct notifier_block nb;
+ void *notifier_handle;
+ bool in_reset;
+};
+
+/**
+ * qiib_driver_data - QSEE IPC IRQ bridge driver data
+ * @list: list of all nodes devices.
+ * @list_lock: lock to synchronize the @list access.
+ * @nprots: Number of device nodes.
+ * @classp: Pointer to the device class.
+ * @dev_num: qiib device number.
+ * @log_ctx: pointer to the ipc logging context.
+ */
+struct qiib_driver_data {
+ struct list_head list;
+ struct mutex list_lock;
+
+ int nports;
+ struct class *classp;
+ dev_t dev_num;
+
+ void *log_ctx;
+};
+
+static struct qiib_driver_data *qiib_info;
+
+/**
+ * qiib_driver_data_init() - Initialize the QIIB driver data.
+ *
+ * This function used to initialize the driver specific data
+ * during the module init.
+ *
+ * Return: 0 for success, Standard Linux errors
+ */
+static int qiib_driver_data_init(void)
+{
+ qiib_info = kzalloc(sizeof(*qiib_info), GFP_KERNEL);
+ if (!qiib_info)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&qiib_info->list);
+ mutex_init(&qiib_info->list_lock);
+
+ qiib_info->log_ctx = ipc_log_context_create(NUM_LOG_PAGES,
+ "qsee_ipc_irq_bridge", 0);
+ if (!qiib_info->log_ctx)
+ QIIB_ERR("%s: unable to create logging context\n", __func__);
+
+ return 0;
+}
+
+/**
+ * qiib_driver_data_deinit() - De-Initialize the QIIB driver data.
+ *
+ * This function used to de-initialize the driver specific data
+ * during the module exit.
+ */
+static void qiib_driver_data_deinit(void)
+{
+ qiib_cleanup();
+ if (!qiib_info->log_ctx)
+ ipc_log_context_destroy(qiib_info->log_ctx);
+ kfree(qiib_info);
+ qiib_info = NULL;
+}
+
+/**
+ * qiib_restart_notifier_cb() - SSR restart notifier callback function
+ * @this: Notifier block used by the SSR framework
+ * @code: The SSR code for which stage of restart is occurring
+ * @data: Structure containing private data - not used here.
+ *
+ * This function is a callback for the SSR framework. From here we initiate
+ * our handling of SSR.
+ *
+ * Return: Status of SSR handling
+ */
+static int qiib_restart_notifier_cb(struct notifier_block *this,
+ unsigned long code,
+ void *data)
+{
+ struct qiib_dev *devp = container_of(this, struct qiib_dev, nb);
+
+ if (code == SUBSYS_BEFORE_SHUTDOWN) {
+ QIIB_DBG("%s: %s: subsystem restart for %s\n", __func__,
+ "SUBSYS_BEFORE_SHUTDOWN",
+ devp->ssr_name);
+ devp->in_reset = true;
+ wake_up_interruptible(&devp->poll_wait_queue);
+ } else if (code == SUBSYS_AFTER_POWERUP) {
+ QIIB_DBG("%s: %s: subsystem restart for %s\n", __func__,
+ "SUBSYS_AFTER_POWERUP",
+ devp->ssr_name);
+ devp->in_reset = false;
+ }
+ return NOTIFY_DONE;
+}
+
+/**
+ * qiib_poll() - poll() syscall for the qiib device
+ * @file: Pointer to the file structure.
+ * @wait: pointer to Poll table.
+ *
+ * This function is used to poll on the qiib device when
+ * userspace client do a poll() system call. All input arguments are
+ * validated by the virtual file system before calling this function.
+ *
+ * Return: POLLIN for interrupt intercepted case and POLLRDHUP for SSR.
+ */
+static unsigned int qiib_poll(struct file *file, poll_table *wait)
+{
+ struct qiib_dev *devp = file->private_data;
+ unsigned int mask = 0;
+ unsigned long flags;
+
+ if (!devp) {
+ QIIB_ERR("%s on NULL device\n", __func__);
+ return POLLERR;
+ }
+
+ if (devp->in_reset)
+ return POLLRDHUP;
+
+ poll_wait(file, &devp->poll_wait_queue, wait);
+ spin_lock_irqsave(&devp->irq_pending_count_lock, flags);
+ if (devp->irq_pending_count) {
+ mask |= POLLIN;
+ QIIB_DBG("%s set POLLIN on [%s] count[%d]\n",
+ __func__, devp->dev_name,
+ devp->irq_pending_count);
+ devp->irq_pending_count = 0;
+ }
+ spin_unlock_irqrestore(&devp->irq_pending_count_lock, flags);
+
+ if (devp->in_reset) {
+ mask |= POLLRDHUP;
+ QIIB_DBG("%s set POLLRDHUP on [%s] count[%d]\n",
+ __func__, devp->dev_name,
+ devp->irq_pending_count);
+ }
+ return mask;
+}
+
+/**
+ * qiib_open() - open() syscall for the qiib device
+ * @inode: Pointer to the inode structure.
+ * @file: Pointer to the file structure.
+ *
+ * This function is used to open the qiib device when
+ * userspace client do a open() system call. All input arguments are
+ * validated by the virtual file system before calling this function.
+ *
+ * Return: 0 for success, Standard Linux errors
+ */
+static int qiib_open(struct inode *inode, struct file *file)
+{
+ struct qiib_dev *devp = NULL;
+
+ devp = container_of(inode->i_cdev, struct qiib_dev, cdev);
+ if (!devp) {
+ QIIB_ERR("%s on NULL device\n", __func__);
+ return -EINVAL;
+ }
+ file->private_data = devp;
+ QIIB_DBG("%s on [%s]\n", __func__, devp->dev_name);
+ return 0;
+}
+
+/**
+ * qiib_release() - release operation on qiibdevice
+ * @inode: Pointer to the inode structure.
+ * @file: Pointer to the file structure.
+ *
+ * This function is used to release the qiib device when
+ * userspace client do a close() system call. All input arguments are
+ * validated by the virtual file system before calling this function.
+ */
+static int qiib_release(struct inode *inode, struct file *file)
+{
+ struct qiib_dev *devp = file->private_data;
+
+ if (!devp) {
+ QIIB_ERR("%s on NULL device\n", __func__);
+ return -EINVAL;
+ }
+
+ QIIB_DBG("%s on [%s]\n", __func__, devp->dev_name);
+ return 0;
+}
+
+static const struct file_operations qiib_fops = {
+ .owner = THIS_MODULE,
+ .open = qiib_open,
+ .release = qiib_release,
+ .poll = qiib_poll,
+};
+
+/**
+ * qiib_add_device() - Initialize qiib device and add cdev
+ * @devp: pointer to the qiib device.
+ * @i: index of the qiib device.
+ *
+ * Return: 0 for success, Standard Linux errors
+ */
+static int qiib_add_device(struct qiib_dev *devp, int i)
+{
+ int ret = 0;
+
+ devp->i = i;
+ init_waitqueue_head(&devp->poll_wait_queue);
+ spin_lock_init(&devp->irq_pending_count_lock);
+
+ cdev_init(&devp->cdev, &qiib_fops);
+ devp->cdev.owner = THIS_MODULE;
+
+ ret = cdev_add(&devp->cdev, qiib_info->dev_num + i, 1);
+ if (IS_ERR_VALUE((unsigned long)ret)) {
+ QIIB_ERR("%s: cdev_add() failed for dev [%s] ret:%i\n",
+ __func__, devp->dev_name, ret);
+ return ret;
+ }
+
+ devp->devicep = device_create(qiib_info->classp,
+ NULL,
+ (qiib_info->dev_num + i),
+ NULL,
+ devp->dev_name);
+
+ if (IS_ERR_OR_NULL(devp->devicep)) {
+ QIIB_ERR("%s: device_create() failed for dev [%s]\n",
+ __func__, devp->dev_name);
+ ret = -ENOMEM;
+ cdev_del(&devp->cdev);
+ return ret;
+ }
+
+ mutex_lock(&qiib_info->list_lock);
+ list_add(&devp->dev_list, &qiib_info->list);
+ mutex_unlock(&qiib_info->list_lock);
+
+ return ret;
+}
+
+static irqreturn_t qiib_irq_handler(int irq, void *priv)
+{
+ struct qiib_dev *devp = priv;
+ unsigned long flags;
+
+ spin_lock_irqsave(&devp->irq_pending_count_lock, flags);
+ devp->irq_pending_count++;
+ spin_unlock_irqrestore(&devp->irq_pending_count_lock, flags);
+ wake_up_interruptible(&devp->poll_wait_queue);
+
+ if (devp->rx_irq_reset_reg)
+ writel_relaxed(devp->irq_mask, devp->rx_irq_reset_reg);
+
+ QIIB_DBG("%s name[%s] pend_count[%d]\n", __func__,
+ devp->dev_name, devp->irq_pending_count);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * qiib_parse_node() - parse node from device tree binding
+ * @node: pointer to device tree node
+ * @devp: pointer to the qiib device
+ *
+ * Return: 0 on success, -ENODEV on failure.
+ */
+static int qiib_parse_node(struct device_node *node, struct qiib_dev *devp)
+{
+ char *key;
+ const char *subsys_name;
+ const char *dev_name;
+ uint32_t irqtype;
+ uint32_t irq_clear[2];
+ struct irq_data *irqtype_data;
+ int ret = -ENODEV;
+
+ key = "qcom,dev-name";
+ dev_name = of_get_property(node, key, NULL);
+ if (!dev_name) {
+ QIIB_ERR("%s: missing key: %s\n", __func__, key);
+ goto missing_key;
+ }
+ QIIB_DBG("%s: %s = %s\n", __func__, key, dev_name);
+
+ key = "interrupts";
+ devp->irq_line = irq_of_parse_and_map(node, 0);
+ if (!devp->irq_line) {
+ QIIB_ERR("%s: missing key: %s\n", __func__, key);
+ goto missing_key;
+ }
+ QIIB_DBG("%s: %s = %d\n", __func__, key, devp->irq_line);
+
+ irqtype_data = irq_get_irq_data(devp->irq_line);
+ if (!irqtype_data) {
+ QIIB_ERR("%s: get irqdata fail:%d\n", __func__, devp->irq_line);
+ goto missing_key;
+ }
+ irqtype = irqd_get_trigger_type(irqtype_data);
+ QIIB_DBG("%s: irqtype = %d\n", __func__, irqtype);
+
+ key = "label";
+ subsys_name = of_get_property(node, key, NULL);
+ if (!subsys_name) {
+ QIIB_ERR("%s: missing key: %s\n", __func__, key);
+ goto missing_key;
+ }
+ QIIB_DBG("%s: %s = %s\n", __func__, key, subsys_name);
+
+ if (irqtype & IRQF_TRIGGER_HIGH) {
+ key = "qcom,rx-irq-clr-mask";
+ ret = of_property_read_u32(node, key, &devp->irq_mask);
+ if (ret) {
+ QIIB_ERR("%s: missing key: %s\n", __func__, key);
+ ret = -ENODEV;
+ goto missing_key;
+ }
+ QIIB_DBG("%s: %s = %d\n", __func__, key, devp->irq_mask);
+
+ key = "qcom,rx-irq-clr";
+ ret = of_property_read_u32_array(node, key, irq_clear,
+ ARRAY_SIZE(irq_clear));
+ if (ret) {
+ QIIB_ERR("%s: missing key: %s\n", __func__, key);
+ ret = -ENODEV;
+ goto missing_key;
+ }
+
+ devp->rx_irq_reset_reg = ioremap_nocache(irq_clear[0],
+ irq_clear[1]);
+ if (!devp->rx_irq_reset_reg) {
+ QIIB_ERR("%s: unable to map rx reset reg\n", __func__);
+ ret = -ENOMEM;
+ goto missing_key;
+ }
+ }
+
+ devp->dev_name = dev_name;
+ devp->ssr_name = subsys_name;
+ devp->nb.notifier_call = qiib_restart_notifier_cb;
+
+ devp->notifier_handle = subsys_notif_register_notifier(devp->ssr_name,
+ &devp->nb);
+ if (IS_ERR_OR_NULL(devp->notifier_handle)) {
+ QIIB_ERR("%s: Could not register SSR notifier cb\n", __func__);
+ ret = -EINVAL;
+ goto ssr_reg_fail;
+ }
+
+ ret = request_irq(devp->irq_line, qiib_irq_handler,
+ irqtype | IRQF_NO_SUSPEND,
+ devp->dev_name, devp);
+ if (ret < 0) {
+ QIIB_ERR("%s: request_irq() failed on %d\n", __func__,
+ devp->irq_line);
+ goto req_irq_fail;
+ } else {
+ ret = enable_irq_wake(devp->irq_line);
+ if (ret < 0)
+ QIIB_ERR("%s: enable_irq_wake() failed on %d\n",
+ __func__, devp->irq_line);
+ }
+
+ return ret;
+
+req_irq_fail:
+ subsys_notif_unregister_notifier(devp->notifier_handle, &devp->nb);
+ssr_reg_fail:
+ if (devp->rx_irq_reset_reg) {
+ iounmap(devp->rx_irq_reset_reg);
+ devp->rx_irq_reset_reg = NULL;
+ }
+missing_key:
+ return ret;
+}
+
+/**
+ * qiib_cleanup - cleanup all the resources
+ *
+ * This function remove all the memory and unregister
+ * the char device region.
+ */
+static void qiib_cleanup(void)
+{
+ struct qiib_dev *devp;
+ struct qiib_dev *index;
+
+ mutex_lock(&qiib_info->list_lock);
+ list_for_each_entry_safe(devp, index, &qiib_info->list, dev_list) {
+ cdev_del(&devp->cdev);
+ list_del(&devp->dev_list);
+ device_destroy(qiib_info->classp,
+ MKDEV(MAJOR(qiib_info->dev_num), devp->i));
+ if (devp->notifier_handle)
+ subsys_notif_unregister_notifier(devp->notifier_handle,
+ &devp->nb);
+ kfree(devp);
+ }
+ mutex_unlock(&qiib_info->list_lock);
+
+ if (!IS_ERR_OR_NULL(qiib_info->classp))
+ class_destroy(qiib_info->classp);
+
+ unregister_chrdev_region(MAJOR(qiib_info->dev_num), qiib_info->nports);
+}
+
+/**
+ * qiib_alloc_chrdev_region() - allocate the char device region
+ *
+ * This function allocate memory for qiib character-device region and
+ * create the class.
+ */
+static int qiib_alloc_chrdev_region(void)
+{
+ int ret;
+
+ ret = alloc_chrdev_region(&qiib_info->dev_num,
+ 0,
+ qiib_info->nports,
+ DEVICE_NAME);
+ if (IS_ERR_VALUE((unsigned long)ret)) {
+ QIIB_ERR("%s: alloc_chrdev_region() failed ret:%i\n",
+ __func__, ret);
+ return ret;
+ }
+
+ qiib_info->classp = class_create(THIS_MODULE, DEVICE_NAME);
+ if (IS_ERR(qiib_info->classp)) {
+ QIIB_ERR("%s: class_create() failed ENOMEM\n", __func__);
+ ret = -ENOMEM;
+ unregister_chrdev_region(MAJOR(qiib_info->dev_num),
+ qiib_info->nports);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int qsee_ipc_irq_bridge_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct device_node *node;
+ struct qiib_dev *devp;
+ int i = 0;
+
+ qiib_info->nports = of_get_available_child_count(pdev->dev.of_node);
+ if (!qiib_info->nports) {
+ QIIB_ERR("%s:Fail nports = %d\n", __func__, qiib_info->nports);
+ return -EINVAL;
+ }
+
+ ret = qiib_alloc_chrdev_region();
+ if (ret) {
+ QIIB_ERR("%s: chrdev_region allocation failed ret:%i\n",
+ __func__, ret);
+ return ret;
+ }
+
+ for_each_available_child_of_node(pdev->dev.of_node, node) {
+ devp = kzalloc(sizeof(*devp), GFP_KERNEL);
+ if (IS_ERR_OR_NULL(devp)) {
+ QIIB_ERR("%s:Allocation failed id:%d\n", __func__, i);
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ ret = qiib_parse_node(node, devp);
+ if (ret) {
+ QIIB_ERR("%s:qiib_parse_node failed %d\n", __func__, i);
+ kfree(devp);
+ goto error;
+ }
+
+ ret = qiib_add_device(devp, i);
+ if (ret < 0) {
+ QIIB_ERR("%s: add [%s] device failed ret=%d\n",
+ __func__, devp->dev_name, ret);
+ kfree(devp);
+ goto error;
+ }
+ i++;
+ }
+
+ QIIB_DBG("%s: Driver Initialized.\n", __func__);
+ return 0;
+
+error:
+ qiib_cleanup();
+ return ret;
+}
+
+static int qsee_ipc_irq_bridge_remove(struct platform_device *pdev)
+{
+ qiib_cleanup();
+ return 0;
+}
+
+static const struct of_device_id qsee_ipc_irq_bridge_match_table[] = {
+ { .compatible = "qcom,qsee-ipc-irq-bridge" },
+ {},
+};
+
+static struct platform_driver qsee_ipc_irq_bridge_driver = {
+ .probe = qsee_ipc_irq_bridge_probe,
+ .remove = qsee_ipc_irq_bridge_remove,
+ .driver = {
+ .name = MODULE_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = qsee_ipc_irq_bridge_match_table,
+ },
+};
+
+static int __init qsee_ipc_irq_bridge_init(void)
+{
+ int ret;
+
+ ret = qiib_driver_data_init();
+ if (ret) {
+ QIIB_ERR("%s: driver data init failed %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ ret = platform_driver_register(&qsee_ipc_irq_bridge_driver);
+ if (ret) {
+ QIIB_ERR("%s: platform driver register failed %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+module_init(qsee_ipc_irq_bridge_init);
+
+static void __exit qsee_ipc_irq_bridge_exit(void)
+{
+ platform_driver_unregister(&qsee_ipc_irq_bridge_driver);
+ qiib_driver_data_deinit();
+}
+module_exit(qsee_ipc_irq_bridge_exit);
+MODULE_DESCRIPTION("QSEE IPC interrupt bridge");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/qcom/scm.c b/drivers/soc/qcom/scm.c
index 68ddd1f..ac5cc54 100644
--- a/drivers/soc/qcom/scm.c
+++ b/drivers/soc/qcom/scm.c
@@ -397,18 +397,22 @@
__asmeq("%1", R1_STR)
__asmeq("%2", R2_STR)
__asmeq("%3", R3_STR)
- __asmeq("%4", R0_STR)
- __asmeq("%5", R1_STR)
- __asmeq("%6", R2_STR)
- __asmeq("%7", R3_STR)
- __asmeq("%8", R4_STR)
- __asmeq("%9", R5_STR)
- __asmeq("%10", R6_STR)
+ __asmeq("%4", R4_STR)
+ __asmeq("%5", R5_STR)
+ __asmeq("%6", R6_STR)
+ __asmeq("%7", R0_STR)
+ __asmeq("%8", R1_STR)
+ __asmeq("%9", R2_STR)
+ __asmeq("%10", R3_STR)
+ __asmeq("%11", R4_STR)
+ __asmeq("%12", R5_STR)
+ __asmeq("%13", R6_STR)
#ifdef REQUIRES_SEC
".arch_extension sec\n"
#endif
"smc #0\n"
- : "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3)
+ : "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3),
+ "=r" (r4), "=r" (r5), "=r" (r6)
: "r" (r0), "r" (r1), "r" (r2), "r" (r3), "r" (r4),
"r" (r5), "r" (r6)
: "x7", "x8", "x9", "x10", "x11", "x12", "x13",
@@ -442,18 +446,22 @@
__asmeq("%1", R1_STR)
__asmeq("%2", R2_STR)
__asmeq("%3", R3_STR)
- __asmeq("%4", R0_STR)
- __asmeq("%5", R1_STR)
- __asmeq("%6", R2_STR)
- __asmeq("%7", R3_STR)
- __asmeq("%8", R4_STR)
- __asmeq("%9", R5_STR)
- __asmeq("%10", R6_STR)
+ __asmeq("%4", R4_STR)
+ __asmeq("%5", R5_STR)
+ __asmeq("%6", R6_STR)
+ __asmeq("%7", R0_STR)
+ __asmeq("%8", R1_STR)
+ __asmeq("%9", R2_STR)
+ __asmeq("%10", R3_STR)
+ __asmeq("%11", R4_STR)
+ __asmeq("%12", R5_STR)
+ __asmeq("%13", R6_STR)
#ifdef REQUIRES_SEC
".arch_extension sec\n"
#endif
"smc #0\n"
- : "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3)
+ : "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3),
+ "=r" (r4), "=r" (r5), "=r" (r6)
: "r" (r0), "r" (r1), "r" (r2), "r" (r3), "r" (r4),
"r" (r5), "r" (r6)
: "x7", "x8", "x9", "x10", "x11", "x12", "x13",
@@ -490,18 +498,22 @@
__asmeq("%1", R1_STR)
__asmeq("%2", R2_STR)
__asmeq("%3", R3_STR)
- __asmeq("%4", R0_STR)
- __asmeq("%5", R1_STR)
- __asmeq("%6", R2_STR)
- __asmeq("%7", R3_STR)
- __asmeq("%8", R4_STR)
- __asmeq("%9", R5_STR)
- __asmeq("%10", R6_STR)
+ __asmeq("%4", R4_STR)
+ __asmeq("%5", R5_STR)
+ __asmeq("%6", R6_STR)
+ __asmeq("%7", R0_STR)
+ __asmeq("%8", R1_STR)
+ __asmeq("%9", R2_STR)
+ __asmeq("%10", R3_STR)
+ __asmeq("%11", R4_STR)
+ __asmeq("%12", R5_STR)
+ __asmeq("%13", R6_STR)
#ifdef REQUIRES_SEC
".arch_extension sec\n"
#endif
"smc #0\n"
- : "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3)
+ : "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3),
+ "=r" (r4), "=r" (r5), "=r" (r6)
: "r" (r0), "r" (r1), "r" (r2), "r" (r3), "r" (r4),
"r" (r5), "r" (r6));
@@ -731,10 +743,6 @@
x0 = fn_id | BIT(SMC_ATOMIC_SYSCALL) | scm_version_mask;
- pr_debug("scm_call: func id %#llx, args: %#x, %#llx, %#llx, %#llx, %#llx\n",
- x0, desc->arginfo, desc->args[0], desc->args[1],
- desc->args[2], desc->x5);
-
if (scm_version == SCM_ARMV8_64)
ret = __scm_call_armv8_64(x0, desc->arginfo, desc->args[0],
desc->args[1], desc->args[2],
@@ -746,9 +754,8 @@
desc->x5, &desc->ret[0],
&desc->ret[1], &desc->ret[2]);
if (ret < 0)
- pr_err("scm_call failed: func id %#llx, arginfo: %#x, args: %#llx, %#llx, %#llx, %#llx, ret: %d, syscall returns: %#llx, %#llx, %#llx\n",
- x0, desc->arginfo, desc->args[0], desc->args[1],
- desc->args[2], desc->x5, ret, desc->ret[0],
+ pr_err("scm_call failed: func id %#llx, ret: %d, syscall returns: %#llx, %#llx, %#llx\n",
+ x0, ret, desc->ret[0],
desc->ret[1], desc->ret[2]);
if (arglen > N_REGISTER_ARGS)
diff --git a/drivers/soc/qcom/service-notifier.c b/drivers/soc/qcom/service-notifier.c
index 221ae0c..f4c67f1 100644
--- a/drivers/soc/qcom/service-notifier.c
+++ b/drivers/soc/qcom/service-notifier.c
@@ -84,6 +84,7 @@
struct ind_req_resp {
char service_path[SERVREG_NOTIF_NAME_LENGTH];
int transaction_id;
+ int curr_state;
};
/*
@@ -200,8 +201,30 @@
struct qmi_servreg_notif_set_ack_req_msg_v01 req;
struct msg_desc req_desc, resp_desc;
struct qmi_servreg_notif_set_ack_resp_msg_v01 resp = { { 0, 0 } };
+ struct service_notif_info *service_notif;
+ enum pd_subsys_state state = USER_PD_STATE_CHANGE;
int rc;
+ service_notif = _find_service_info(data->ind_msg.service_path);
+ if (!service_notif)
+ return;
+ if ((int)data->ind_msg.curr_state < QMI_STATE_MIN_VAL ||
+ (int)data->ind_msg.curr_state > QMI_STATE_MAX_VAL)
+ pr_err("Unexpected indication notification state %d\n",
+ data->ind_msg.curr_state);
+ else {
+ mutex_lock(¬if_add_lock);
+ mutex_lock(&service_list_lock);
+ rc = service_notif_queue_notification(service_notif,
+ data->ind_msg.curr_state, &state);
+ if (rc & NOTIFY_STOP_MASK)
+ pr_err("Notifier callback aborted for %s with error %d\n",
+ data->ind_msg.service_path, rc);
+ service_notif->curr_state = data->ind_msg.curr_state;
+ mutex_unlock(&service_list_lock);
+ mutex_unlock(¬if_add_lock);
+ }
+
req.transaction_id = data->ind_msg.transaction_id;
snprintf(req.service_name, ARRAY_SIZE(req.service_name), "%s",
data->ind_msg.service_path);
@@ -236,11 +259,9 @@
unsigned int msg_len, void *ind_cb_priv)
{
struct qmi_client_info *data = (struct qmi_client_info *)ind_cb_priv;
- struct service_notif_info *service_notif;
struct msg_desc ind_desc;
struct qmi_servreg_notif_state_updated_ind_msg_v01 ind_msg = {
QMI_STATE_MIN_VAL, "", 0xFFFF };
- enum pd_subsys_state state = USER_PD_STATE_CHANGE;
int rc;
ind_desc.msg_id = SERVREG_NOTIF_STATE_UPDATED_IND_MSG;
@@ -256,27 +277,8 @@
ind_msg.service_name, ind_msg.curr_state,
ind_msg.transaction_id);
- service_notif = _find_service_info(ind_msg.service_name);
- if (!service_notif)
- return;
-
- if ((int)ind_msg.curr_state < QMI_STATE_MIN_VAL ||
- (int)ind_msg.curr_state > QMI_STATE_MAX_VAL)
- pr_err("Unexpected indication notification state %d\n",
- ind_msg.curr_state);
- else {
- mutex_lock(¬if_add_lock);
- mutex_lock(&service_list_lock);
- rc = service_notif_queue_notification(service_notif,
- ind_msg.curr_state, &state);
- if (rc & NOTIFY_STOP_MASK)
- pr_err("Notifier callback aborted for %s with error %d\n",
- ind_msg.service_name, rc);
- service_notif->curr_state = ind_msg.curr_state;
- mutex_unlock(&service_list_lock);
- mutex_unlock(¬if_add_lock);
- }
data->ind_msg.transaction_id = ind_msg.transaction_id;
+ data->ind_msg.curr_state = ind_msg.curr_state;
snprintf(data->ind_msg.service_path,
ARRAY_SIZE(data->ind_msg.service_path), "%s",
ind_msg.service_name);
@@ -373,6 +375,12 @@
mutex_unlock(&qmi_client_release_lock);
pr_info("Connection established between QMI handle and %d service\n",
data->instance_id);
+ /* Register for indication messages about service */
+ rc = qmi_register_ind_cb(data->clnt_handle,
+ root_service_service_ind_cb, (void *)data);
+ if (rc < 0)
+ pr_err("Indication callback register failed(instance-id: %d) rc:%d\n",
+ data->instance_id, rc);
mutex_lock(¬if_add_lock);
mutex_lock(&service_list_lock);
list_for_each_entry(service_notif, &service_list, list) {
@@ -395,12 +403,6 @@
}
mutex_unlock(&service_list_lock);
mutex_unlock(¬if_add_lock);
- /* Register for indication messages about service */
- rc = qmi_register_ind_cb(data->clnt_handle,
- root_service_service_ind_cb, (void *)data);
- if (rc < 0)
- pr_err("Indication callback register failed(instance-id: %d) rc:%d\n",
- data->instance_id, rc);
}
static void root_service_service_exit(struct qmi_client_info *data,
diff --git a/drivers/soc/qcom/subsys-pil-tz.c b/drivers/soc/qcom/subsys-pil-tz.c
index f8f6829..01eb260 100644
--- a/drivers/soc/qcom/subsys-pil-tz.c
+++ b/drivers/soc/qcom/subsys-pil-tz.c
@@ -795,6 +795,33 @@
return rc;
}
+static int pil_deinit_image_trusted(struct pil_desc *pil)
+{
+ struct pil_tz_data *d = desc_to_data(pil);
+ u32 proc, scm_ret = 0;
+ int rc;
+ struct scm_desc desc = {0};
+
+ if (d->subsys_desc.no_auth)
+ return 0;
+
+ desc.args[0] = proc = d->pas_id;
+ desc.arginfo = SCM_ARGS(1);
+
+ if (!is_scm_armv8()) {
+ rc = scm_call(SCM_SVC_PIL, PAS_SHUTDOWN_CMD, &proc,
+ sizeof(proc), &scm_ret, sizeof(scm_ret));
+ } else {
+ rc = scm_call2(SCM_SIP_FNID(SCM_SVC_PIL, PAS_SHUTDOWN_CMD),
+ &desc);
+ scm_ret = desc.ret[0];
+ }
+
+ if (rc)
+ return rc;
+ return scm_ret;
+}
+
static struct pil_reset_ops pil_ops_trusted = {
.init_image = pil_init_image_trusted,
.mem_setup = pil_mem_setup_trusted,
@@ -802,6 +829,7 @@
.shutdown = pil_shutdown_trusted,
.proxy_vote = pil_make_proxy_vote,
.proxy_unvote = pil_remove_proxy_vote,
+ .deinit_image = pil_deinit_image_trusted,
};
static void log_failure_reason(const struct pil_tz_data *d)
diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
index ad3eb187..37766d29 100644
--- a/drivers/spi/spi-geni-qcom.c
+++ b/drivers/spi/spi-geni-qcom.c
@@ -23,7 +23,6 @@
#define SPI_NUM_CHIPSELECT (4)
#define SPI_XFER_TIMEOUT_MS (250)
-#define SPI_OVERSAMPLING (2)
/* SPI SE specific registers */
#define SE_SPI_CPHA (0x224)
#define SE_SPI_LOOPBACK (0x22C)
@@ -100,6 +99,7 @@
struct spi_transfer *cur_xfer;
struct completion xfer_done;
struct device *wrapper_dev;
+ int oversampling;
};
static struct spi_master *get_spi_master(struct device *dev)
@@ -123,7 +123,8 @@
clk_sel &= ~CLK_SEL_MSK;
m_clk_cfg &= ~CLK_DIV_MSK;
- ret = geni_se_clk_freq_match(&mas->spi_rsc, speed_hz, &idx,
+ ret = geni_se_clk_freq_match(&mas->spi_rsc,
+ (speed_hz * mas->oversampling), &idx,
&sclk_freq, true);
if (ret) {
dev_err(mas->dev, "%s: Failed(%d) to find src clk for 0x%x\n",
@@ -131,17 +132,23 @@
return ret;
}
- div = ((sclk_freq / SPI_OVERSAMPLING) / speed_hz);
- if (!div)
+ div = ((sclk_freq / mas->oversampling) / speed_hz);
+ if (!div) {
+ dev_err(mas->dev, "%s:Err:sclk:%lu oversampling:%d speed:%u\n",
+ __func__, sclk_freq, mas->oversampling, speed_hz);
return -EINVAL;
+ }
dev_dbg(mas->dev, "%s: req %u sclk %lu, idx %d, div %d\n", __func__,
speed_hz, sclk_freq, idx, div);
clk_sel |= (idx & CLK_SEL_MSK);
m_clk_cfg |= ((div << CLK_DIV_SHFT) | SER_CLK_EN);
ret = clk_set_rate(rsc->se_clk, sclk_freq);
- if (ret)
+ if (ret) {
+ dev_err(mas->dev, "%s: clk_set_rate failed %d\n",
+ __func__, ret);
return ret;
+ }
geni_write_reg(clk_sel, mas->base, SE_GENI_CLK_SEL);
geni_write_reg(m_clk_cfg, mas->base, GENI_SER_M_CLK_CFG);
@@ -238,6 +245,10 @@
if (unlikely(!mas->setup)) {
int proto = get_se_proto(mas->base);
+ unsigned int major;
+ unsigned int minor;
+ unsigned int step;
+ int hw_ver;
if (unlikely(proto != SPI)) {
dev_err(mas->dev, "Invalid proto %d\n", proto);
@@ -248,12 +259,24 @@
mas->tx_fifo_depth = get_tx_fifo_depth(mas->base);
mas->rx_fifo_depth = get_rx_fifo_depth(mas->base);
mas->tx_fifo_width = get_tx_fifo_width(mas->base);
+ mas->oversampling = 1;
/* Transmit an entire FIFO worth of data per IRQ */
mas->tx_wm = 1;
dev_dbg(mas->dev, "tx_fifo %d rx_fifo %d tx_width %d\n",
mas->tx_fifo_depth, mas->rx_fifo_depth,
mas->tx_fifo_width);
mas->setup = true;
+ hw_ver = geni_se_qupv3_hw_version(mas->wrapper_dev, &major,
+ &minor, &step);
+ if (hw_ver)
+ dev_err(mas->dev, "%s:Err getting HW version %d\n",
+ __func__, hw_ver);
+ else {
+ dev_dbg(mas->dev, "%s:Major:%d Minor:%d step:%d\n",
+ __func__, major, minor, step);
+ if ((major == 1) && (minor == 0))
+ mas->oversampling = 2;
+ }
}
exit_prepare_transfer_hardware:
return ret;
diff --git a/drivers/staging/android/ion/ion_cma_heap.c b/drivers/staging/android/ion/ion_cma_heap.c
index ee8e8b6..fbf7542 100644
--- a/drivers/staging/android/ion/ion_cma_heap.c
+++ b/drivers/staging/android/ion/ion_cma_heap.c
@@ -241,11 +241,13 @@
static void ion_secure_cma_free(struct ion_buffer *buffer)
{
- int ret = 0;
+ int i, ret = 0;
int *source_vm_list;
int source_nelems;
int dest_vmid;
int dest_perms;
+ struct sg_table *sgt;
+ struct scatterlist *sg;
struct ion_cma_buffer_info *info = buffer->priv_virt;
source_nelems = count_set_bits(buffer->flags & ION_FLAGS_CP_MASK);
@@ -264,7 +266,8 @@
dest_vmid = VMID_HLOS;
dest_perms = PERM_READ | PERM_WRITE | PERM_EXEC;
- ret = hyp_assign_table(info->table, source_vm_list, source_nelems,
+ sgt = info->table;
+ ret = hyp_assign_table(sgt, source_vm_list, source_nelems,
&dest_vmid, &dest_perms, 1);
if (ret) {
pr_err("%s: Not freeing memory since assign failed\n",
@@ -272,6 +275,9 @@
goto out_free_source;
}
+ for_each_sg(sgt->sgl, sg, sgt->nents, i)
+ ClearPagePrivate(sg_page(sgt->sgl));
+
ion_cma_free(buffer);
out_free_source:
kfree(source_vm_list);
@@ -282,13 +288,15 @@
struct ion_buffer *buffer, unsigned long len,
unsigned long align, unsigned long flags)
{
- int ret = 0;
+ int i, ret = 0;
int count;
int source_vm;
int *dest_vm_list = NULL;
int *dest_perms = NULL;
int dest_nelems;
struct ion_cma_buffer_info *info;
+ struct sg_table *sgt;
+ struct scatterlist *sg;
source_vm = VMID_HLOS;
@@ -327,13 +335,18 @@
}
info = buffer->priv_virt;
- ret = hyp_assign_table(info->table, &source_vm, 1,
- dest_vm_list, dest_perms, dest_nelems);
+ sgt = info->table;
+ ret = hyp_assign_table(sgt, &source_vm, 1, dest_vm_list, dest_perms,
+ dest_nelems);
if (ret) {
pr_err("%s: Assign call failed\n", __func__);
goto err;
}
+ /* Set the private bit to indicate that we've secured this */
+ for_each_sg(sgt->sgl, sg, sgt->nents, i)
+ SetPagePrivate(sg_page(sgt->sgl));
+
kfree(dest_vm_list);
kfree(dest_perms);
return ret;
diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c
index 17cdac4..533c708 100644
--- a/drivers/tty/serial/msm_geni_serial.c
+++ b/drivers/tty/serial/msm_geni_serial.c
@@ -107,9 +107,12 @@
#define UART_CORE2X_VOTE (10000)
#define WAKEBYTE_TIMEOUT_MSEC (2000)
-#define IPC_LOG_PWR_PAGES (2)
-#define IPC_LOG_MISC_PAGES (2)
-#define IPC_LOG_TX_RX_PAGES (3)
+#define WAIT_XFER_MAX_ITER (50)
+#define WAIT_XFER_MAX_TIMEOUT_US (10000)
+#define WAIT_XFER_MIN_TIMEOUT_US (9000)
+#define IPC_LOG_PWR_PAGES (6)
+#define IPC_LOG_MISC_PAGES (6)
+#define IPC_LOG_TX_RX_PAGES (8)
#define DATA_BYTES_PER_LINE (32)
#define IPC_LOG_MSG(ctx, x...) do { \
@@ -146,6 +149,7 @@
void *ipc_log_misc;
unsigned int cur_baud;
int ioctl_count;
+ int edge_count;
};
static const struct uart_ops msm_geni_serial_pops;
@@ -221,27 +225,66 @@
(unsigned int)addr, size, buf);
}
-static bool check_tx_active(struct uart_port *uport)
+static bool check_transfers_inflight(struct uart_port *uport)
{
- /*
- * Poll if the GENI STATUS bit for TX is cleared. If the bit is
- * clear (poll condition met), return false, meaning tx isn't active
- * else return true. So return not of the poll return.
- */
- return !msm_geni_serial_poll_bit(uport, SE_GENI_STATUS,
- M_GENI_CMD_ACTIVE, false);
+ bool xfer_on = false;
+ bool tx_active = false;
+ bool tx_empty = false;
+ bool m_cmd_active = false;
+ bool rx_active = false;
+ u32 rx_fifo_status = 0;
+ u32 geni_status = geni_read_reg_nolog(uport->membase,
+ SE_GENI_STATUS);
+ /* Possible stop tx is called multiple times. */
+ m_cmd_active = geni_status & M_GENI_CMD_ACTIVE;
+ tx_empty = msm_geni_serial_tx_empty(uport);
+ tx_active = m_cmd_active || !tx_empty;
+ rx_fifo_status = geni_read_reg_nolog(uport->membase,
+ SE_GENI_RX_FIFO_STATUS);
+ if (rx_fifo_status)
+ rx_active = true;
+
+ if (rx_active || tx_active)
+ xfer_on = true;
+
+ return xfer_on;
+}
+
+static void wait_for_transfers_inflight(struct uart_port *uport)
+{
+ int iter = 0;
+ struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
+
+ while (iter < WAIT_XFER_MAX_ITER) {
+ if (check_transfers_inflight(uport)) {
+ usleep_range(WAIT_XFER_MIN_TIMEOUT_US,
+ WAIT_XFER_MAX_TIMEOUT_US);
+ iter++;
+ } else {
+ break;
+ }
+ }
+ if (check_transfers_inflight(uport)) {
+ u32 geni_status = geni_read_reg_nolog(uport->membase,
+ SE_GENI_STATUS);
+ u32 geni_ios = geni_read_reg_nolog(uport->membase, SE_GENI_IOS);
+ u32 rx_fifo_status = geni_read_reg_nolog(uport->membase,
+ SE_GENI_RX_FIFO_STATUS);
+
+ IPC_LOG_MSG(port->ipc_log_misc,
+ "%s IOS 0x%x geni status 0x%x rx fifo 0x%x\n",
+ __func__, geni_ios, geni_status, rx_fifo_status);
+ }
}
static int vote_clock_on(struct uart_port *uport)
{
- int ret = 0;
struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
- int usage_count = atomic_read(&uport->dev->power.usage_count);
+ int ret = 0;
if (!pm_runtime_enabled(uport->dev)) {
dev_err(uport->dev, "RPM not available.Can't enable clocks\n");
- ret = -EPERM;
- return ret;
+ return -EPERM;
}
ret = msm_geni_serial_power_on(uport);
if (ret) {
@@ -249,39 +292,31 @@
return ret;
}
port->ioctl_count++;
- __pm_relax(&port->geni_wake);
- IPC_LOG_MSG(port->ipc_log_pwr, "%s rpm %d ioctl %d\n",
- __func__, usage_count, port->ioctl_count);
+ IPC_LOG_MSG(port->ipc_log_pwr, "%s%s ioctl %d\n", __func__,
+ current->comm, port->ioctl_count);
return 0;
}
static int vote_clock_off(struct uart_port *uport)
{
struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
- int ret = 0;
- int usage_count = atomic_read(&uport->dev->power.usage_count);
if (!pm_runtime_enabled(uport->dev)) {
dev_err(uport->dev, "RPM not available.Can't enable clocks\n");
- ret = -EPERM;
- return ret;
+ return -EPERM;
}
- /* Check on going Tx. Don't block on this for now. */
- if (check_tx_active(uport))
- dev_warn(uport->dev, "%s: Vote off called during active Tx",
- __func__);
if (!port->ioctl_count) {
dev_warn(uport->dev, "%s:Imbalanced vote off ioctl %d\n",
- __func__, usage_count);
+ __func__, port->ioctl_count);
IPC_LOG_MSG(port->ipc_log_pwr,
- "%s:Imbalanced vote_off from userspace rpm%d",
- __func__, usage_count);
- return 0;
+ "%s:Imbalanced vote_off from userspace. %d",
+ __func__, port->ioctl_count);
+ return -EPERM;
}
port->ioctl_count--;
msm_geni_serial_power_off(uport);
- IPC_LOG_MSG(port->ipc_log_pwr, "%s rpm %d ioctl %d\n",
- __func__, usage_count, port->ioctl_count);
+ IPC_LOG_MSG(port->ipc_log_pwr, "%s%s ioctl %d\n", __func__,
+ current->comm, port->ioctl_count);
return 0;
};
@@ -311,14 +346,11 @@
static void msm_geni_serial_break_ctl(struct uart_port *uport, int ctl)
{
- if (!uart_console(uport) && pm_runtime_status_suspended(uport->dev)) {
- dev_err(uport->dev, "%s Device suspended,vote clocks on.\n",
- __func__);
+ if (!uart_console(uport) && pm_runtime_status_suspended(uport->dev))
return;
- }
if (ctl) {
- check_tx_active(uport);
+ wait_for_transfers_inflight(uport);
geni_setup_m_cmd(uport->membase, UART_START_BREAK, 0);
} else {
geni_setup_m_cmd(uport->membase, UART_STOP_BREAK, 0);
@@ -357,11 +389,8 @@
{
u32 uart_manual_rfr = 0;
- if (pm_runtime_status_suspended(uport->dev)) {
- dev_info(uport->dev, "%sDevice suspended,vote clocks on\n",
- __func__);
+ if (pm_runtime_status_suspended(uport->dev))
return;
- }
if (!(mctrl & TIOCM_RTS))
uart_manual_rfr |= (UART_MANUAL_RFR_EN | UART_RFR_NOT_READY);
geni_write_reg_nolog(uart_manual_rfr, uport->membase,
@@ -396,9 +425,12 @@
static int msm_geni_serial_power_on(struct uart_port *uport)
{
int ret = 0;
+ struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
ret = pm_runtime_get_sync(uport->dev);
if (ret < 0) {
+ IPC_LOG_MSG(port->ipc_log_pwr, "%s Err\n", __func__);
+ WARN_ON_ONCE(1);
pm_runtime_put_noidle(uport->dev);
pm_runtime_set_suspended(uport->dev);
return ret;
@@ -693,6 +725,8 @@
if (!uart_console(uport) && pm_runtime_status_suspended(uport->dev)) {
dev_err(uport->dev, "%s.Device is suspended.\n", __func__);
+ IPC_LOG_MSG(msm_port->ipc_log_misc,
+ "%s.Device is suspended.\n", __func__);
return;
}
@@ -719,8 +753,12 @@
unsigned int geni_status;
struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
- if (!uart_console(uport) && pm_runtime_status_suspended(uport->dev))
+ if (!uart_console(uport) && pm_runtime_status_suspended(uport->dev)) {
+ dev_err(uport->dev, "%s.Device is suspended.\n", __func__);
+ IPC_LOG_MSG(port->ipc_log_misc,
+ "%s.Device is suspended.\n", __func__);
return;
+ }
geni_m_irq_en = geni_read_reg_nolog(uport->membase, SE_GENI_M_IRQ_EN);
geni_m_irq_en &= ~(M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN);
@@ -755,8 +793,12 @@
unsigned int geni_status;
struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
- if (!uart_console(uport) && pm_runtime_status_suspended(uport->dev))
+ if (!uart_console(uport) && pm_runtime_status_suspended(uport->dev)) {
+ dev_err(uport->dev, "%s.Device is suspended.\n", __func__);
+ IPC_LOG_MSG(port->ipc_log_misc,
+ "%s.Device is suspended.\n", __func__);
return;
+ }
geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS);
if (geni_status & S_GENI_CMD_ACTIVE)
@@ -787,9 +829,14 @@
unsigned int geni_s_irq_en;
unsigned int geni_m_irq_en;
unsigned int geni_status;
+ struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
- if (!uart_console(uport) && pm_runtime_status_suspended(uport->dev))
+ if (!uart_console(uport) && pm_runtime_status_suspended(uport->dev)) {
+ dev_err(uport->dev, "%s.Device is suspended.\n", __func__);
+ IPC_LOG_MSG(port->ipc_log_misc,
+ "%s.Device is suspended.\n", __func__);
return;
+ }
geni_s_irq_en = geni_read_reg_nolog(uport->membase,
SE_GENI_S_IRQ_EN);
@@ -943,12 +990,17 @@
struct uart_port *uport = dev;
unsigned long flags;
unsigned int m_irq_en;
+ struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport);
spin_lock_irqsave(&uport->lock, flags);
if (uart_console(uport) && uport->suspended)
goto exit_geni_serial_isr;
- if (!uart_console(uport) && pm_runtime_status_suspended(uport->dev))
+ if (!uart_console(uport) && pm_runtime_status_suspended(uport->dev)) {
+ dev_err(uport->dev, "%s.Device is suspended.\n", __func__);
+ IPC_LOG_MSG(msm_port->ipc_log_misc,
+ "%s.Device is suspended.\n", __func__);
goto exit_geni_serial_isr;
+ }
m_irq_status = geni_read_reg_nolog(uport->membase,
SE_GENI_M_IRQ_STATUS);
s_irq_status = geni_read_reg_nolog(uport->membase,
@@ -986,16 +1038,19 @@
unsigned long flags;
spin_lock_irqsave(&uport->lock, flags);
- if (port->wakeup_byte) {
+ IPC_LOG_MSG(port->ipc_log_rx, "%s: Edge-Count %d\n", __func__,
+ port->edge_count);
+ if (port->wakeup_byte && (port->edge_count == 2)) {
tty = uport->state->port.tty;
tty_insert_flip_char(tty->port, port->wakeup_byte, TTY_NORMAL);
IPC_LOG_MSG(port->ipc_log_rx, "%s: Inject 0x%x\n",
__func__, port->wakeup_byte);
+ port->edge_count = 0;
tty_flip_buffer_push(tty->port);
+ __pm_wakeup_event(&port->geni_wake, WAKEBYTE_TIMEOUT_MSEC);
+ } else if (port->edge_count < 2) {
+ port->edge_count++;
}
- __pm_wakeup_event(&port->geni_wake, WAKEBYTE_TIMEOUT_MSEC);
- IPC_LOG_MSG(port->ipc_log_misc, "%s:Holding Wake Lock for %d ms\n",
- __func__, WAKEBYTE_TIMEOUT_MSEC);
spin_unlock_irqrestore(&uport->lock, flags);
return IRQ_HANDLED;
}
@@ -1052,8 +1107,12 @@
unsigned long flags;
/* Stop the console before stopping the current tx */
- if (uart_console(uport))
+ if (uart_console(uport)) {
console_stop(uport->cons);
+ } else {
+ msm_geni_serial_power_on(uport);
+ wait_for_transfers_inflight(uport);
+ }
spin_lock_irqsave(&uport->lock, flags);
msm_geni_serial_stop_tx(uport);
@@ -1065,12 +1124,12 @@
if (uart_console(uport)) {
se_geni_resources_off(&msm_port->serial_rsc);
} else {
+ msm_geni_serial_power_off(uport);
if (msm_port->wakeup_irq > 0) {
+ irq_set_irq_wake(msm_port->wakeup_irq, 0);
disable_irq(msm_port->wakeup_irq);
free_irq(msm_port->wakeup_irq, msm_port);
}
- __pm_relax(&msm_port->geni_wake);
- msm_geni_serial_power_off(uport);
}
IPC_LOG_MSG(msm_port->ipc_log_misc, "%s\n", __func__);
}
@@ -1183,8 +1242,11 @@
if (likely(!uart_console(uport))) {
ret = msm_geni_serial_power_on(&msm_port->uport);
- if (ret)
- goto exit_startup;
+ if (ret) {
+ dev_err(uport->dev, "%s:Failed to power on %d\n",
+ __func__, ret);
+ return ret;
+ }
}
if (unlikely(get_se_proto(uport->membase) != UART)) {
@@ -1217,8 +1279,7 @@
}
if (msm_port->wakeup_irq > 0) {
- ret = request_threaded_irq(msm_port->wakeup_irq, NULL,
- msm_geni_wakeup_isr,
+ ret = request_irq(msm_port->wakeup_irq, msm_geni_wakeup_isr,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"hs_uart_wakeup", uport);
if (unlikely(ret)) {
@@ -1227,9 +1288,17 @@
goto exit_startup;
}
disable_irq(msm_port->wakeup_irq);
+ ret = irq_set_irq_wake(msm_port->wakeup_irq, 1);
+ if (unlikely(ret)) {
+ dev_err(uport->dev, "%s:Failed to set IRQ wake:%d\n",
+ __func__, ret);
+ goto exit_startup;
+ }
}
IPC_LOG_MSG(msm_port->ipc_log_misc, "%s\n", __func__);
exit_startup:
+ if (likely(!uart_console(uport)))
+ msm_geni_serial_power_off(&msm_port->uport);
return ret;
}
@@ -1316,6 +1385,11 @@
struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
unsigned long clk_rate;
+ if (!uart_console(uport) && pm_runtime_status_suspended(uport->dev)) {
+ IPC_LOG_MSG(port->ipc_log_pwr,
+ "%s Device suspended,vote clocks on.\n", __func__);
+ return;
+ }
/* baud rate */
baud = uart_get_baud_rate(uport, termios, old, 300, 4000000);
port->cur_baud = baud;
@@ -1412,7 +1486,13 @@
{
unsigned int tx_fifo_status;
unsigned int is_tx_empty = 1;
+ struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
+ if (!uart_console(uport) && pm_runtime_status_suspended(uport->dev)) {
+ IPC_LOG_MSG(port->ipc_log_pwr,
+ "%s Device suspended,vote clocks on.\n", __func__);
+ return 1;
+ }
tx_fifo_status = geni_read_reg_nolog(uport->membase,
SE_GENI_TX_FIFO_STATUS);
if (tx_fifo_status)
@@ -1671,6 +1751,7 @@
bool is_console = false;
struct platform_device *wrapper_pdev;
struct device_node *wrapper_ph_node;
+ u32 wake_char = 0;
id = of_match_device(msm_geni_device_tbl, &pdev->dev);
if (id) {
@@ -1733,9 +1814,14 @@
if (ret)
goto exit_geni_serial_probe;
- if (of_property_read_u8(pdev->dev.of_node, "qcom,wakeup-byte",
- &dev_port->wakeup_byte))
- dev_info(&pdev->dev, "No Wakeup byte specified\n");
+ if (of_property_read_u32(pdev->dev.of_node, "qcom,wakeup-byte",
+ &wake_char)) {
+ dev_dbg(&pdev->dev, "No Wakeup byte specified\n");
+ } else {
+ dev_port->wakeup_byte = (u8)wake_char;
+ dev_info(&pdev->dev, "Wakeup byte 0x%x\n",
+ dev_port->wakeup_byte);
+ }
dev_port->serial_rsc.se_clk = devm_clk_get(&pdev->dev, "se-clk");
if (IS_ERR(dev_port->serial_rsc.se_clk)) {
@@ -1857,14 +1943,28 @@
struct msm_geni_serial_port *port = platform_get_drvdata(pdev);
int ret = 0;
+ wait_for_transfers_inflight(&port->uport);
ret = se_geni_resources_off(&port->serial_rsc);
if (ret) {
dev_err(dev, "%s: Error ret %d\n", __func__, ret);
goto exit_runtime_suspend;
}
- if (port->wakeup_irq > 0)
+ disable_irq(port->uport.irq);
+ if (port->wakeup_irq > 0) {
+ struct se_geni_rsc *rsc = &port->serial_rsc;
+
+ port->edge_count = 0;
+ ret = pinctrl_select_state(rsc->geni_pinctrl,
+ rsc->geni_gpio_active);
+ if (ret) {
+ dev_err(dev, "%s: Error %d pinctrl_select_state\n",
+ __func__, ret);
+ goto exit_runtime_suspend;
+ }
enable_irq(port->wakeup_irq);
+ }
IPC_LOG_MSG(port->ipc_log_pwr, "%s:\n", __func__);
+ __pm_relax(&port->geni_wake);
exit_runtime_suspend:
return ret;
}
@@ -1875,13 +1975,21 @@
struct msm_geni_serial_port *port = platform_get_drvdata(pdev);
int ret = 0;
+ /*
+ * Do an unconditional relax followed by a stay awake in case the
+ * wake source is activated by the wakeup isr.
+ */
+ __pm_relax(&port->geni_wake);
+ __pm_stay_awake(&port->geni_wake);
if (port->wakeup_irq > 0)
disable_irq(port->wakeup_irq);
ret = se_geni_resources_on(&port->serial_rsc);
if (ret) {
dev_err(dev, "%s: Error ret %d\n", __func__, ret);
+ __pm_relax(&port->geni_wake);
goto exit_runtime_resume;
}
+ enable_irq(port->uport.irq);
IPC_LOG_MSG(port->ipc_log_pwr, "%s:\n", __func__);
exit_runtime_resume:
return ret;
@@ -1897,10 +2005,20 @@
uart_suspend_port((struct uart_driver *)uport->private_data,
uport);
} else {
+ struct uart_state *state = uport->state;
+ struct tty_port *tty_port = &state->port;
+
+ mutex_lock(&tty_port->mutex);
if (!pm_runtime_status_suspended(dev)) {
- dev_info(dev, "%s: Is still active\n", __func__);
+ dev_err(dev, "%s:Active userspace vote; ioctl_cnt %d\n",
+ __func__, port->ioctl_count);
+ IPC_LOG_MSG(port->ipc_log_pwr,
+ "%s:Active userspace vote; ioctl_cnt %d\n",
+ __func__, port->ioctl_count);
+ mutex_unlock(&tty_port->mutex);
return -EBUSY;
}
+ mutex_unlock(&tty_port->mutex);
}
return 0;
}
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 0dc81d2..69d617f 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -55,6 +55,8 @@
#include "debug.h"
#include "xhci.h"
+#define SDP_CONNETION_CHECK_TIME 10000 /* in ms */
+
/* time out to wait for USB cable status notification (in ms)*/
#define SM_INIT_TIMEOUT 30000
@@ -262,6 +264,7 @@
int pm_qos_latency;
struct pm_qos_request pm_qos_req_dma;
struct delayed_work perf_vote_work;
+ struct delayed_work sdp_check;
};
#define USB_HSPHY_3P3_VOL_MIN 3050000 /* uV */
@@ -2818,6 +2821,25 @@
return NOTIFY_DONE;
}
+
+static void check_for_sdp_connection(struct work_struct *w)
+{
+ struct dwc3_msm *mdwc =
+ container_of(w, struct dwc3_msm, sdp_check.work);
+ struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
+
+ if (!mdwc->vbus_active)
+ return;
+
+ /* floating D+/D- lines detected */
+ if (dwc->gadget.state < USB_STATE_DEFAULT &&
+ dwc3_gadget_get_link_state(dwc) != DWC3_LINK_STATE_CMPLY) {
+ mdwc->vbus_active = 0;
+ dbg_event(0xFF, "Q RW SPD CHK", mdwc->vbus_active);
+ queue_work(mdwc->dwc3_wq, &mdwc->resume_work);
+ }
+}
+
static int dwc3_msm_vbus_notifier(struct notifier_block *nb,
unsigned long event, void *ptr)
{
@@ -3104,6 +3126,7 @@
INIT_WORK(&mdwc->vbus_draw_work, dwc3_msm_vbus_draw_work);
INIT_DELAYED_WORK(&mdwc->sm_work, dwc3_otg_sm_work);
INIT_DELAYED_WORK(&mdwc->perf_vote_work, msm_dwc3_perf_vote_work);
+ INIT_DELAYED_WORK(&mdwc->sdp_check, check_for_sdp_connection);
mdwc->dwc3_wq = alloc_ordered_workqueue("dwc3_wq", 0);
if (!mdwc->dwc3_wq) {
@@ -3859,34 +3882,46 @@
return 0;
}
-static int dwc3_msm_gadget_vbus_draw(struct dwc3_msm *mdwc, unsigned int mA)
+static int get_psy_type(struct dwc3_msm *mdwc)
{
union power_supply_propval pval = {0};
- int ret;
if (mdwc->charging_disabled)
- return 0;
-
- if (mdwc->max_power == mA)
- return 0;
+ return -EINVAL;
if (!mdwc->usb_psy) {
mdwc->usb_psy = power_supply_get_by_name("usb");
if (!mdwc->usb_psy) {
- dev_warn(mdwc->dev, "Could not get usb power_supply\n");
+ dev_err(mdwc->dev, "Could not get usb psy\n");
return -ENODEV;
}
}
- power_supply_get_property(mdwc->usb_psy,
- POWER_SUPPLY_PROP_REAL_TYPE, &pval);
- if (pval.intval != POWER_SUPPLY_TYPE_USB)
+ power_supply_get_property(mdwc->usb_psy, POWER_SUPPLY_PROP_REAL_TYPE,
+ &pval);
+
+ return pval.intval;
+}
+
+static int dwc3_msm_gadget_vbus_draw(struct dwc3_msm *mdwc, unsigned int mA)
+{
+ union power_supply_propval pval = {0};
+ int ret, psy_type;
+
+ if (mdwc->max_power == mA)
return 0;
- dev_info(mdwc->dev, "Avail curr from USB = %u\n", mA);
+ psy_type = get_psy_type(mdwc);
+ if (psy_type == POWER_SUPPLY_TYPE_USB) {
+ dev_info(mdwc->dev, "Avail curr from USB = %u\n", mA);
+ /* Set max current limit in uA */
+ pval.intval = 1000 * mA;
+ } else if (psy_type == POWER_SUPPLY_TYPE_USB_FLOAT) {
+ pval.intval = -ETIMEDOUT;
+ } else {
+ return 0;
+ }
- /* Set max current limit in uA */
- pval.intval = 1000 * mA;
ret = power_supply_set_property(mdwc->usb_psy,
POWER_SUPPLY_PROP_CURRENT_MAX, &pval);
if (ret) {
@@ -3957,6 +3992,10 @@
work = 1;
} else if (test_bit(B_SESS_VLD, &mdwc->inputs)) {
dev_dbg(mdwc->dev, "b_sess_vld\n");
+ if (get_psy_type(mdwc) == POWER_SUPPLY_TYPE_USB_FLOAT)
+ queue_delayed_work(mdwc->dwc3_wq,
+ &mdwc->sdp_check,
+ msecs_to_jiffies(SDP_CONNETION_CHECK_TIME));
/*
* Increment pm usage count upon cable connect. Count
* is decremented in OTG_STATE_B_PERIPHERAL state on
@@ -3979,6 +4018,7 @@
!test_bit(ID, &mdwc->inputs)) {
dev_dbg(mdwc->dev, "!id || !bsv\n");
mdwc->otg_state = OTG_STATE_B_IDLE;
+ cancel_delayed_work_sync(&mdwc->sdp_check);
dwc3_otg_start_peripheral(mdwc, 0);
/*
* Decrement pm usage count upon cable disconnect
@@ -4011,6 +4051,7 @@
if (!test_bit(B_SESS_VLD, &mdwc->inputs)) {
dev_dbg(mdwc->dev, "BSUSP: !bsv\n");
mdwc->otg_state = OTG_STATE_B_IDLE;
+ cancel_delayed_work_sync(&mdwc->sdp_check);
dwc3_otg_start_peripheral(mdwc, 0);
} else if (!test_bit(B_SUSPEND, &mdwc->inputs)) {
dev_dbg(mdwc->dev, "BSUSP !susp\n");
diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c
index 141b916..2831a0f 100644
--- a/drivers/usb/pd/policy_engine.c
+++ b/drivers/usb/pd/policy_engine.c
@@ -926,6 +926,7 @@
if (pd->psy_type == POWER_SUPPLY_TYPE_USB ||
pd->psy_type == POWER_SUPPLY_TYPE_USB_CDP ||
+ pd->psy_type == POWER_SUPPLY_TYPE_USB_FLOAT ||
usb_compliance_mode)
start_usb_peripheral(pd);
}
diff --git a/include/dt-bindings/clock/qcom,aop-qmp.h b/include/dt-bindings/clock/qcom,aop-qmp.h
index b88dc36..7898c47 100644
--- a/include/dt-bindings/clock/qcom,aop-qmp.h
+++ b/include/dt-bindings/clock/qcom,aop-qmp.h
@@ -25,5 +25,5 @@
/* clocks id */
#define QDSS_CLK 0
-
+#define QDSS_AO_CLK 1
#endif
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index 9f93d18..edf88bd 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -40,6 +40,7 @@
CPUHP_SLAB_PREPARE,
CPUHP_MD_RAID5_PREPARE,
CPUHP_RCUTREE_PREP,
+ CPUHP_CORE_CTL_ISOLATION_DEAD,
CPUHP_CPUIDLE_COUPLED_PREPARE,
CPUHP_POWERPC_PMAC_PREPARE,
CPUHP_POWERPC_MMU_CTX_PREPARE,
diff --git a/include/linux/hdcp_qseecom.h b/include/linux/hdcp_qseecom.h
new file mode 100644
index 0000000..20f5cba
--- /dev/null
+++ b/include/linux/hdcp_qseecom.h
@@ -0,0 +1,224 @@
+/* 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __HDCP_QSEECOM_H
+#define __HDCP_QSEECOM_H
+#include <linux/types.h>
+
+#define HDCP_MAX_MESSAGE_PARTS 4
+
+/**
+ * enum hdcp_lib_wakeup_cmd - commands for interacting with HDCP driver
+ * @HDCP_LIB_WKUP_CMD_INVALID: initialization value
+ * @HDCP_LIB_WKUP_CMD_START: start authentication
+ * @HDCP_LIB_WKUP_CMD_STOP: stop authentication
+ * @HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS: sending message to sink succeeded
+ * @HDCP_LIB_WKUP_CMD_MSG_SEND_FAILED: sending message to sink failed
+ * @HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS: receiving message from sink succeeded
+ * @HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED: receiving message from sink failed
+ * @HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT: receiving message from sink timed out
+ * @HDCP_LIB_WKUP_CMD_QUERY_STREAM_TYPE: start content stream processing
+ * @HDCP_LIB_WKUP_CMD_LINK_FAILED: link failure notification
+ */
+enum hdcp_lib_wakeup_cmd {
+ HDCP_LIB_WKUP_CMD_INVALID,
+ HDCP_LIB_WKUP_CMD_START,
+ HDCP_LIB_WKUP_CMD_STOP,
+ HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS,
+ HDCP_LIB_WKUP_CMD_MSG_SEND_FAILED,
+ HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS,
+ HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED,
+ HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT,
+ HDCP_LIB_WKUP_CMD_QUERY_STREAM_TYPE,
+ HDCP_LIB_WKUP_CMD_LINK_FAILED,
+};
+
+/**
+ * enum hdcp_wakeup_cmd - commands for interacting with display transport layer
+ * @HDCP_WKUP_CMD_INVALID: initialization value
+ * @HDCP_WKUP_CMD_SEND_MESSAGE: send message to sink
+ * @HDCP_WKUP_CMD_RECV_MESSAGE: receive message from sink
+ * @HDCP_WKUP_CMD_STATUS_SUCCESS: successfully communicated with TrustZone
+ * @HDCP_WKUP_CMD_STATUS_FAILED: failed to communicate with TrustZone
+ * @HDCP_WKUP_CMD_LINK_POLL: poll the HDCP link
+ * @HDCP_WKUP_CMD_AUTHENTICATE: start authentication
+ */
+enum hdcp_wakeup_cmd {
+ HDCP_WKUP_CMD_INVALID,
+ HDCP_WKUP_CMD_SEND_MESSAGE,
+ HDCP_WKUP_CMD_RECV_MESSAGE,
+ HDCP_WKUP_CMD_STATUS_SUCCESS,
+ HDCP_WKUP_CMD_STATUS_FAILED,
+ HDCP_WKUP_CMD_LINK_POLL,
+ HDCP_WKUP_CMD_AUTHENTICATE
+};
+
+/**
+ * struct hdcp_lib_wakeup_data - command and data send to HDCP driver
+ * @cmd: command type
+ * @context: void pointer to the HDCP driver instance
+ * @recvd_msg_buf: message received from the sink
+ * @recvd_msg_len: length of message received from the sink
+ * @timeout: time out value for timed transactions
+ */
+struct hdcp_lib_wakeup_data {
+ enum hdcp_lib_wakeup_cmd cmd;
+ void *context;
+ char *recvd_msg_buf;
+ uint32_t recvd_msg_len;
+ uint32_t timeout;
+};
+
+/**
+ * struct hdcp_msg_part - a single part of an HDCP 2.2 message
+ * @name: user readable message name
+ * @offset: message part offset
+ * @length message part length
+ */
+struct hdcp_msg_part {
+ char *name;
+ uint32_t offset;
+ uint32_t length;
+};
+
+/**
+ * struct hdcp_msg_data - a full HDCP 2.2 message containing one or more parts
+ * @num_messages: total number of parts in a full message
+ * @messages: array containing num_messages parts
+ * @rx_status: value of rx_status register
+ */
+struct hdcp_msg_data {
+ uint32_t num_messages;
+ struct hdcp_msg_part messages[HDCP_MAX_MESSAGE_PARTS];
+ uint8_t rx_status;
+};
+
+/**
+ * struct hdcp_wakeup_data - command and data sent to display transport layer
+ * @cmd: command type
+ * @context: void pointer to the display transport layer
+ * @send_msg_buf: buffer containing message to be sent to sink
+ * @send_msg_len: length of the message to be sent to sink
+ * @timeout: timeout value for timed transactions
+ * @abort_mask: mask used to determine whether HDCP link is valid
+ * @message_data: a pointer to the message description
+ */
+struct hdcp_wakeup_data {
+ enum hdcp_wakeup_cmd cmd;
+ void *context;
+ char *send_msg_buf;
+ uint32_t send_msg_len;
+ uint32_t timeout;
+ uint8_t abort_mask;
+ const struct hdcp_msg_data *message_data;
+};
+
+static inline char *hdcp_cmd_to_str(uint32_t cmd)
+{
+ switch (cmd) {
+ case HDCP_WKUP_CMD_SEND_MESSAGE:
+ return "HDCP_WKUP_CMD_SEND_MESSAGE";
+ case HDCP_WKUP_CMD_RECV_MESSAGE:
+ return "HDCP_WKUP_CMD_RECV_MESSAGE";
+ case HDCP_WKUP_CMD_STATUS_SUCCESS:
+ return "HDCP_WKUP_CMD_STATUS_SUCCESS";
+ case HDCP_WKUP_CMD_STATUS_FAILED:
+ return "HDCP_WKUP_CMD_STATUS_FAIL";
+ case HDCP_WKUP_CMD_LINK_POLL:
+ return "HDCP_WKUP_CMD_LINK_POLL";
+ case HDCP_WKUP_CMD_AUTHENTICATE:
+ return "HDCP_WKUP_CMD_AUTHENTICATE";
+ default:
+ return "???";
+ }
+}
+
+static inline char *hdcp_lib_cmd_to_str(uint32_t cmd)
+{
+ switch (cmd) {
+ case HDCP_LIB_WKUP_CMD_START:
+ return "HDCP_LIB_WKUP_CMD_START";
+ case HDCP_LIB_WKUP_CMD_STOP:
+ return "HDCP_LIB_WKUP_CMD_STOP";
+ case HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS:
+ return "HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS";
+ case HDCP_LIB_WKUP_CMD_MSG_SEND_FAILED:
+ return "HDCP_LIB_WKUP_CMD_MSG_SEND_FAILED";
+ case HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS:
+ return "HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS";
+ case HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED:
+ return "HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED";
+ case HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT:
+ return "HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT";
+ case HDCP_LIB_WKUP_CMD_QUERY_STREAM_TYPE:
+ return "HDCP_LIB_WKUP_CMD_QUERY_STREAM_TYPE";
+ case HDCP_LIB_WKUP_CMD_LINK_FAILED:
+ return "HDCP_LIB_WKUP_CMD_LINK_FAILED";
+ default:
+ return "???";
+ }
+}
+
+/**
+ * struct hdcp_txmtr_ops - interface to HDCP Driver
+ * @wakeup: wake the HDCP driver with a new command
+ * @feature_supported: checks for HDCP support on the target device
+ */
+struct hdcp_txmtr_ops {
+ int (*wakeup)(struct hdcp_lib_wakeup_data *data);
+ bool (*feature_supported)(void *phdcpcontext);
+};
+
+/**
+ * struct hdcp_client_ops - call back functions to display transport layer
+ * @wakeup: wake up display transport layer with a new command
+ * @notify_lvl_change notify of encryption level changes
+ */
+struct hdcp_client_ops {
+ int (*wakeup)(struct hdcp_wakeup_data *data);
+ void (*notify_lvl_change)(void *client_ctx, int min_lvl);
+};
+
+/**
+ * enum hdcp_device_type - display interface types
+ * @HDCP_TXMTR_HDMI: HDMI interface
+ * @HDCP_TXMTR_DP: DisplayPort interface
+ */
+enum hdcp_device_type {
+ HDCP_TXMTR_HDMI = 0x8001,
+ HDCP_TXMTR_DP = 0x8002
+};
+
+/**
+ * struct hdcp_register_data - data used in HDCP driver clients' registration
+ * @client_ops: call back functions from the client
+ * @txmtr_ops: HDCP driver interface
+ * @device_type: display interface type of the client
+ * @client_ctx: void pointer to client data object
+ * @hdcp_ctx: void pointer to HDCP driver reference for client use
+ */
+struct hdcp_register_data {
+ struct hdcp_client_ops *client_ops;
+ struct hdcp_txmtr_ops *txmtr_ops;
+ enum hdcp_device_type device_type;
+ void *client_ctx;
+ void **hdcp_ctx;
+};
+
+int hdcp_library_register(struct hdcp_register_data *data);
+void hdcp_library_deregister(void *phdcpcontext);
+bool hdcp1_check_if_supported_load_app(void);
+int hdcp1_set_keys(uint32_t *aksv_msb, uint32_t *aksv_lsb);
+int hdcp1_set_enc(bool enable);
+void hdcp1_cache_repeater_topology(void *hdcp1_cached_tp);
+void hdcp1_notify_topology(void);
+#endif /* __HDCP_QSEECOM_H */
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 558adfa..8f5af30 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1921,6 +1921,13 @@
}
#endif /* CONFIG_SECURITY_SELINUX_DISABLE */
+/* Currently required to handle SELinux runtime hook disable. */
+#ifdef CONFIG_SECURITY_WRITABLE_HOOKS
+#define __lsm_ro_after_init
+#else
+#define __lsm_ro_after_init __ro_after_init
+#endif /* CONFIG_SECURITY_WRITABLE_HOOKS */
+
extern int __init security_module_enable(const char *module);
extern void __init capability_add_hooks(void);
#ifdef CONFIG_SECURITY_YAMA
diff --git a/include/linux/random.h b/include/linux/random.h
index 16ab429..1fa0dc8 100644
--- a/include/linux/random.h
+++ b/include/linux/random.h
@@ -42,8 +42,42 @@
extern const struct file_operations random_fops, urandom_fops;
#endif
-unsigned int get_random_int(void);
-unsigned long get_random_long(void);
+u32 get_random_u32(void);
+u64 get_random_u64(void);
+static inline unsigned int get_random_int(void)
+{
+ return get_random_u32();
+}
+static inline unsigned long get_random_long(void)
+{
+#if BITS_PER_LONG == 64
+ return get_random_u64();
+#else
+ return get_random_u32();
+#endif
+}
+
+/*
+ * On 64-bit architectures, protect against non-terminated C string overflows
+ * by zeroing out the first byte of the canary; this leaves 56 bits of entropy.
+ */
+#ifdef CONFIG_64BIT
+# ifdef __LITTLE_ENDIAN
+# define CANARY_MASK 0xffffffffffffff00UL
+# else /* big endian, 64 bits: */
+# define CANARY_MASK 0x00ffffffffffffffUL
+# endif
+#else /* 32 bits: */
+# define CANARY_MASK 0xffffffffUL
+#endif
+
+static inline unsigned long get_random_canary(void)
+{
+ unsigned long val = get_random_long();
+
+ return val & CANARY_MASK;
+}
+
unsigned long randomize_page(unsigned long start, unsigned long range);
u32 prandom_u32(void);
diff --git a/include/soc/qcom/msm-core.h b/include/soc/qcom/msm-core.h
index cd44615..f1c06a6 100644
--- a/include/soc/qcom/msm-core.h
+++ b/include/soc/qcom/msm-core.h
@@ -16,9 +16,12 @@
#ifdef CONFIG_APSS_CORE_EA
void set_cpu_throttled(struct cpumask *mask, bool throttling);
struct blocking_notifier_head *get_power_update_notifier(void);
+void trigger_cpu_pwr_stats_calc(void);
+struct cpu_pwr_stats *get_cpu_pwr_stats(void);
#else
static inline void set_cpu_throttled(struct cpumask *mask, bool throttling) {}
struct blocking_notifier_head *get_power_update_notifier(void) {return NULL; }
+static inline void trigger_cpu_pwr_stats_calc(void) {}
+struct cpu_pwr_stats *get_cpu_pwr_stats(void) {return NULL; }
#endif
#endif
-
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 14f6445..aa95178 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -8537,6 +8537,8 @@
#define VSS_ICOMMON_CMD_GET_PARAM_V2 0x0001133E
#define VSS_ICOMMON_RSP_GET_PARAM 0x00011008
+#define VSS_MAX_AVCS_NUM_SERVICES 25
+
/* ID of the Bass Boost module.
* This module supports the following parameter IDs:
* - #AUDPROC_PARAM_ID_BASS_BOOST_ENABLE
@@ -9197,6 +9199,74 @@
*/
} __packed;
+/* Q6Core Specific */
+#define AVCS_CMD_GET_FWK_VERSION (0x0001292C)
+#define AVCS_CMDRSP_GET_FWK_VERSION (0x0001292D)
+
+#define AVCS_SERVICE_ID_ALL (0xFFFFFFFF)
+#define APRV2_IDS_SERVICE_ID_ADSP_CVP_V (0xB)
+
+struct avcs_get_fwk_version {
+ /*
+ * Indicates the major version of the AVS build.
+ * This value is incremented on chipset family boundaries.
+ */
+ uint32_t build_major_version;
+
+ /*
+ * Minor version of the AVS build.
+ * This value represents the mainline to which the AVS build belongs.
+ */
+ uint32_t build_minor_version;
+
+ /* Indicates the AVS branch version to which the image belongs. */
+ uint32_t build_branch_version;
+
+ /* Indicates the AVS sub-branch or customer product line information. */
+ uint32_t build_subbranch_version;
+
+ /* Number of supported AVS services in the current build. */
+ uint32_t num_services;
+};
+
+struct avs_svc_api_info {
+ /*
+ * APRV2 service IDs for the individual static services.
+ *
+ * @values
+ * - APRV2_IDS_SERVICE_ID_ADSP_CORE_V
+ * - APRV2_IDS_SERVICE_ID_ADSP_AFE_V
+ * - APRV2_IDS_SERVICE_ID_ADSP_ASM_V
+ * - APRV2_IDS_SERVICE_ID_ADSP_ADM_V
+ * - APRV2_IDS_SERVICE_ID_ADSP_MVM_V
+ * - APRV2_IDS_SERVICE_ID_ADSP_CVS_V
+ * - APRV2_IDS_SERVICE_ID_ADSP_CVP_V
+ * - APRV2_IDS_SERVICE_ID_ADSP_LSM_V
+ */
+ uint32_t service_id;
+
+ /*
+ * Indicates the API version of the service.
+ *
+ * Each new API update that warrants a change on the HLOS side triggers
+ * an increment in the version.
+ */
+ uint32_t api_version;
+
+ /*
+ * Indicates the API increments on a sub-branch (not on the mainline).
+ *
+ * API branch version numbers can increment independently on different
+ * sub-branches.
+ */
+ uint32_t api_branch_version;
+};
+
+struct avcs_fwk_ver_info {
+ struct avcs_get_fwk_version avcs_fwk_version;
+ struct avs_svc_api_info *services;
+} __packed;
+
/* LSM Specific */
#define VW_FEAT_DIM (39)
diff --git a/include/sound/q6core.h b/include/sound/q6core.h
index 0b8309a..111af67 100644
--- a/include/sound/q6core.h
+++ b/include/sound/q6core.h
@@ -13,6 +13,7 @@
#ifndef __Q6CORE_H__
#define __Q6CORE_H__
#include <linux/qdsp6v2/apr.h>
+#include <sound/apr_audio-v2.h>
@@ -21,6 +22,11 @@
bool q6core_is_adsp_ready(void);
+int q6core_get_service_version(uint32_t service_id,
+ struct avcs_fwk_ver_info *ver_info,
+ size_t size);
+size_t q6core_get_avcs_service_size(uint32_t service_id);
+
#define ADSP_CMD_SET_DTS_EAGLE_DATA_ID 0x00012919
#define DTS_EAGLE_LICENSE_ID 0x00028346
struct adsp_dts_eagle {
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 2ac75e2..d1bed63 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -358,6 +358,32 @@
EVENT_ALL = EVENT_FLEXIBLE | EVENT_PINNED,
};
+/* The shared events struct. */
+#define SHARED_EVENTS_MAX 7
+
+struct shared_events_str {
+ /*
+ * Mutex to serialize access to shared list. Needed for the
+ * read/modify/write sequences.
+ */
+ struct mutex list_mutex;
+
+ /*
+ * A 1 bit for an index indicates that the slot is being used for
+ * an event. A 0 means that the slot can be used.
+ */
+ DECLARE_BITMAP(used_mask, SHARED_EVENTS_MAX);
+
+ /*
+ * The kernel events that are shared for a cpu;
+ */
+ struct perf_event *events[SHARED_EVENTS_MAX];
+ struct perf_event_attr attr[SHARED_EVENTS_MAX];
+ atomic_t refcount[SHARED_EVENTS_MAX];
+};
+
+static struct shared_events_str __percpu *shared_events;
+
/*
* perf_sched_events : >0 events exist
* perf_cgroup_events: >0 per-cpu cgroup events exist on this cpu
@@ -4079,6 +4105,35 @@
static void perf_addr_filters_splice(struct perf_event *event,
struct list_head *head);
+static int
+perf_event_delete_kernel_shared(struct perf_event *event)
+{
+ int rc = -1, cpu = event->cpu;
+ struct shared_events_str *shrd_events;
+ unsigned long idx;
+
+ if (!shared_events || (u32)cpu >= nr_cpu_ids)
+ return 0;
+
+ shrd_events = per_cpu_ptr(shared_events, cpu);
+
+ mutex_lock(&shrd_events->list_mutex);
+
+ for_each_set_bit(idx, shrd_events->used_mask, SHARED_EVENTS_MAX) {
+ if (shrd_events->events[idx] == event) {
+ if (atomic_dec_and_test(&shrd_events->refcount[idx])) {
+ clear_bit(idx, shrd_events->used_mask);
+ shrd_events->events[idx] = NULL;
+ }
+ rc = (int)atomic_read(&shrd_events->refcount[idx]);
+ break;
+ }
+ }
+
+ mutex_unlock(&shrd_events->list_mutex);
+ return rc;
+}
+
static void _free_event(struct perf_event *event)
{
irq_work_sync(&event->pending);
@@ -4216,8 +4271,12 @@
goto no_ctx;
}
- if (!is_kernel_event(event))
+ if (!is_kernel_event(event)) {
perf_remove_from_owner(event);
+ } else {
+ if (perf_event_delete_kernel_shared(event) > 0)
+ return 0;
+ }
ctx = perf_event_ctx_lock(event);
WARN_ON_ONCE(ctx->parent_ctx);
@@ -10043,6 +10102,103 @@
return err;
}
+static struct perf_event *
+perf_event_create_kernel_shared_check(struct perf_event_attr *attr, int cpu,
+ struct task_struct *task,
+ perf_overflow_handler_t overflow_handler,
+ void *context)
+{
+ unsigned long idx;
+ struct perf_event *event;
+ struct shared_events_str *shrd_events;
+
+ /*
+ * Have to be per cpu events for sharing
+ */
+ if (!shared_events || (u32)cpu >= nr_cpu_ids)
+ return NULL;
+
+ /*
+ * Can't handle these type requests for sharing right now.
+ */
+ if (task || context || overflow_handler ||
+ (attr->type != PERF_TYPE_HARDWARE &&
+ attr->type != PERF_TYPE_RAW))
+ return NULL;
+
+ /*
+ * Using per_cpu_ptr (or could do cross cpu call which is what most of
+ * perf does to access per cpu data structures
+ */
+ shrd_events = per_cpu_ptr(shared_events, cpu);
+
+ mutex_lock(&shrd_events->list_mutex);
+
+ event = NULL;
+ for_each_set_bit(idx, shrd_events->used_mask, SHARED_EVENTS_MAX) {
+ if (memcmp(attr, &shrd_events->attr[idx],
+ sizeof(shrd_events->attr[idx])) == 0) {
+ atomic_inc(&shrd_events->refcount[idx]);
+ event = shrd_events->events[idx];
+ break;
+ }
+ }
+ mutex_unlock(&shrd_events->list_mutex);
+ return event;
+}
+
+static void
+perf_event_create_kernel_shared_add(struct perf_event_attr *attr, int cpu,
+ struct task_struct *task,
+ perf_overflow_handler_t overflow_handler,
+ void *context,
+ struct perf_event *event)
+{
+ unsigned long idx;
+ struct shared_events_str *shrd_events;
+
+ /*
+ * Have to be per cpu events for sharing
+ */
+ if (!shared_events || (u32)cpu >= nr_cpu_ids)
+ return;
+
+ /*
+ * Can't handle these type requests for sharing right now.
+ */
+ if (task || context || overflow_handler ||
+ (attr->type != PERF_TYPE_HARDWARE &&
+ attr->type != PERF_TYPE_RAW))
+ return;
+
+ /*
+ * Using per_cpu_ptr (or could do cross cpu call which is what most of
+ * perf does to access per cpu data structures
+ */
+ shrd_events = per_cpu_ptr(shared_events, cpu);
+
+ mutex_lock(&shrd_events->list_mutex);
+
+ /*
+ * If we are in this routine, we know that this event isn't already in
+ * the shared list. Check if slot available in shared list
+ */
+ idx = find_first_zero_bit(shrd_events->used_mask, SHARED_EVENTS_MAX);
+
+ if (idx >= SHARED_EVENTS_MAX)
+ goto out;
+
+ /*
+ * The event isn't in the list and there is an empty slot so add it.
+ */
+ shrd_events->attr[idx] = *attr;
+ shrd_events->events[idx] = event;
+ set_bit(idx, shrd_events->used_mask);
+ atomic_set(&shrd_events->refcount[idx], 1);
+out:
+ mutex_unlock(&shrd_events->list_mutex);
+}
+
/**
* perf_event_create_kernel_counter
*
@@ -10061,6 +10217,14 @@
int err;
/*
+ * Check if the requested attributes match a shared event
+ */
+ event = perf_event_create_kernel_shared_check(attr, cpu,
+ task, overflow_handler, context);
+ if (event)
+ return event;
+
+ /*
* Get the target context (task or percpu):
*/
@@ -10096,6 +10260,11 @@
perf_unpin_context(ctx);
mutex_unlock(&ctx->mutex);
+ /*
+ * Check if can add event to shared list
+ */
+ perf_event_create_kernel_shared_add(attr, cpu,
+ task, overflow_handler, context, event);
return event;
err_unlock:
@@ -10919,10 +11088,21 @@
void __init perf_event_init(void)
{
- int ret;
+ int ret, cpu;
idr_init(&pmu_idr);
+ shared_events = alloc_percpu(struct shared_events_str);
+ if (!shared_events) {
+ WARN(1, "alloc_percpu failed for shared_events struct");
+ } else {
+ for_each_possible_cpu(cpu) {
+ struct shared_events_str *shrd_events =
+ per_cpu_ptr(shared_events, cpu);
+
+ mutex_init(&shrd_events->list_mutex);
+ }
+ }
perf_event_init_all_cpus();
init_srcu_struct(&pmus_srcu);
perf_pmu_register(&perf_swevent, "software", PERF_TYPE_SOFTWARE);
diff --git a/kernel/fork.c b/kernel/fork.c
index 52e5505..39c0709 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1517,6 +1517,18 @@
if (!p)
goto fork_out;
+ /*
+ * This _must_ happen before we call free_task(), i.e. before we jump
+ * to any of the bad_fork_* labels. This is to avoid freeing
+ * p->set_child_tid which is (ab)used as a kthread's data pointer for
+ * kernel threads (PF_KTHREAD).
+ */
+ p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL;
+ /*
+ * Clear TID on mm_release()?
+ */
+ p->clear_child_tid = (clone_flags & CLONE_CHILD_CLEARTID) ? child_tidptr : NULL;
+
ftrace_graph_init_task(p);
rt_mutex_init_task(p);
@@ -1678,11 +1690,6 @@
}
}
- p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL;
- /*
- * Clear TID on mm_release()?
- */
- p->clear_child_tid = (clone_flags & CLONE_CHILD_CLEARTID) ? child_tidptr : NULL;
#ifdef CONFIG_BLOCK
p->plug = NULL;
#endif
diff --git a/kernel/irq/cpuhotplug.c b/kernel/irq/cpuhotplug.c
index 007482b..4684b75 100644
--- a/kernel/irq/cpuhotplug.c
+++ b/kernel/irq/cpuhotplug.c
@@ -69,7 +69,7 @@
if (!c->irq_set_affinity) {
pr_debug("IRQ%u: unable to set affinity\n", d->irq);
} else {
- int r = irq_do_set_affinity(d, affinity, false);
+ int r = irq_set_affinity_locked(d, affinity, false);
if (r)
pr_warn_ratelimited("IRQ%u: set affinity failed(%d).\n",
d->irq, r);
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index d706c96..7722ade 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -5958,12 +5958,6 @@
set_rq_online(rq);
raw_spin_unlock(&rq->lock);
- /*
- * We might have been in tickless state. Clear NOHZ flags to avoid
- * us being kicked for helping out with balancing
- */
- nohz_balance_clear_nohz_mask(cpu);
-
clear_walt_request(cpu);
local_irq_enable();
return 0;
diff --git a/kernel/sched/core_ctl.c b/kernel/sched/core_ctl.c
index 4c3bf526..e56af41 100644
--- a/kernel/sched/core_ctl.c
+++ b/kernel/sched/core_ctl.c
@@ -13,7 +13,6 @@
#define pr_fmt(fmt) "core_ctl: " fmt
#include <linux/init.h>
-#include <linux/notifier.h>
#include <linux/cpu.h>
#include <linux/cpumask.h>
#include <linux/cpufreq.h>
@@ -877,21 +876,18 @@
return 0;
}
-static int __ref cpu_callback(struct notifier_block *nfb,
- unsigned long action, void *hcpu)
+static int isolation_cpuhp_state(unsigned int cpu, bool online)
{
- uint32_t cpu = (uintptr_t)hcpu;
struct cpu_data *state = &per_cpu(cpu_state, cpu);
struct cluster_data *cluster = state->cluster;
unsigned int need;
- bool do_wakeup, unisolated = false;
+ bool do_wakeup = false, unisolated = false;
unsigned long flags;
if (unlikely(!cluster || !cluster->inited))
- return NOTIFY_DONE;
+ return 0;
- switch (action & ~CPU_TASKS_FROZEN) {
- case CPU_ONLINE:
+ if (online) {
cluster->active_cpus = get_active_cpu_count(cluster);
/*
@@ -901,9 +897,7 @@
* reject trying to online CPUs.
*/
move_cpu_lru(state);
- break;
-
- case CPU_DEAD:
+ } else {
/*
* We don't want to have a CPU both offline and isolated.
* So unisolate a CPU that went down if it was isolated by us.
@@ -919,9 +913,6 @@
state->busy = 0;
cluster->active_cpus = get_active_cpu_count(cluster);
- break;
- default:
- return NOTIFY_DONE;
}
need = apply_limits(cluster, cluster->need_cpus);
@@ -933,12 +924,18 @@
if (do_wakeup)
wake_up_core_ctl_thread(cluster);
- return NOTIFY_OK;
+ return 0;
}
-static struct notifier_block __refdata cpu_notifier = {
- .notifier_call = cpu_callback,
-};
+static int core_ctl_isolation_online_cpu(unsigned int cpu)
+{
+ return isolation_cpuhp_state(cpu, true);
+}
+
+static int core_ctl_isolation_dead_cpu(unsigned int cpu)
+{
+ return isolation_cpuhp_state(cpu, false);
+}
/* ============================ init code ============================== */
@@ -1068,7 +1065,13 @@
if (should_skip(cpu_possible_mask))
return 0;
- register_cpu_notifier(&cpu_notifier);
+ cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
+ "core_ctl/isolation:online",
+ core_ctl_isolation_online_cpu, NULL);
+
+ cpuhp_setup_state_nocalls(CPUHP_CORE_CTL_ISOLATION_DEAD,
+ "core_ctl/isolation:dead",
+ NULL, core_ctl_isolation_dead_cpu);
for_each_cpu(cpu, &cpus) {
int ret;
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index b31522e..62a29ed 100755
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -9888,6 +9888,8 @@
if (sd) {
cpumask_and(&cpumask, nohz.idle_cpus_mask,
sched_domain_span(sd));
+ cpumask_andnot(&cpumask, &cpumask,
+ cpu_isolated_mask);
ilb = cpumask_first(&cpumask);
}
rcu_read_unlock();
@@ -9896,8 +9898,11 @@
if (!energy_aware() ||
(capacity_orig_of(cpu) ==
cpu_rq(cpu)->rd->max_cpu_capacity.val ||
- cpu_overutilized(cpu)))
- ilb = cpumask_first(nohz.idle_cpus_mask);
+ cpu_overutilized(cpu))) {
+ cpumask_andnot(&cpumask, nohz.idle_cpus_mask,
+ cpu_isolated_mask);
+ ilb = cpumask_first(&cpumask);
+ }
}
if (ilb < nr_cpu_ids && idle_cpu(ilb))
@@ -9934,21 +9939,16 @@
return;
}
-void nohz_balance_clear_nohz_mask(int cpu)
-{
- if (likely(cpumask_test_cpu(cpu, nohz.idle_cpus_mask))) {
- cpumask_clear_cpu(cpu, nohz.idle_cpus_mask);
- atomic_dec(&nohz.nr_cpus);
- }
-}
-
void nohz_balance_exit_idle(unsigned int cpu)
{
if (unlikely(test_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu)))) {
/*
* Completely isolated CPUs don't ever set, so we must test.
*/
- nohz_balance_clear_nohz_mask(cpu);
+ if (likely(cpumask_test_cpu(cpu, nohz.idle_cpus_mask))) {
+ cpumask_clear_cpu(cpu, nohz.idle_cpus_mask);
+ atomic_dec(&nohz.nr_cpus);
+ }
clear_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu));
}
}
@@ -10223,6 +10223,7 @@
int nr_busy;
int cpu = rq->cpu;
bool kick = false;
+ cpumask_t cpumask;
if (unlikely(rq->idle_balance))
return false;
@@ -10238,7 +10239,8 @@
* None are in tickless mode and hence no need for NOHZ idle load
* balancing.
*/
- if (likely(!atomic_read(&nohz.nr_cpus)))
+ cpumask_andnot(&cpumask, nohz.idle_cpus_mask, cpu_isolated_mask);
+ if (cpumask_empty(&cpumask))
return false;
if (time_before(now, nohz.next_balance))
@@ -10272,8 +10274,7 @@
}
sd = rcu_dereference(per_cpu(sd_asym, cpu));
- if (sd && (cpumask_first_and(nohz.idle_cpus_mask,
- sched_domain_span(sd)) < cpu)) {
+ if (sd && (cpumask_first_and(&cpumask, sched_domain_span(sd)) < cpu)) {
kick = true;
goto unlock;
}
@@ -10297,6 +10298,13 @@
CPU_IDLE : CPU_NOT_IDLE;
/*
+ * Since core isolation doesn't update nohz.idle_cpus_mask, there
+ * is a possibility this nohz kicked cpu could be isolated. Hence
+ * return if the cpu is isolated.
+ */
+ if (cpu_isolated(this_rq->cpu))
+ return;
+ /*
* If this cpu has a pending nohz_balance_kick, then do the
* balancing on behalf of the other idle cpus whose ticks are
* stopped. Do nohz_idle_balance *before* rebalance_domains to
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 14c62f4..318d289 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -1444,7 +1444,6 @@
extern void update_group_capacity(struct sched_domain *sd, int cpu);
extern void trigger_load_balance(struct rq *rq);
-extern void nohz_balance_clear_nohz_mask(int cpu);
extern void set_cpus_allowed_common(struct task_struct *p, const struct cpumask *new_mask);
diff --git a/net/wireless/db.txt b/net/wireless/db.txt
index a2dff71..413deff 100644
--- a/net/wireless/db.txt
+++ b/net/wireless/db.txt
@@ -538,6 +538,12 @@
(5490 - 5730 @ 160), (24), DFS
(5735 - 5835 @ 80), (30)
+country GI: DFS-ETSI
+ (2402 - 2482 @ 40), (20)
+ (5170 - 5250 @ 80), (23), AUTO-BW
+ (5250 - 5330 @ 80), (23), DFS, AUTO-BW
+ (5490 - 5710 @ 160), (30), DFS
+
country GL: DFS-ETSI
(2402 - 2482 @ 40), (20)
(5170 - 5250 @ 80), (23), AUTO-BW
@@ -678,10 +684,6 @@
(5170 - 5330 @ 160), (23)
(5735 - 5835 @ 80), (30)
-country IR:
- (2402 - 2482 @ 40), (20)
- (5735 - 5835 @ 80), (30)
-
country IS: DFS-ETSI
(2402 - 2482 @ 40), (20)
(5170 - 5250 @ 80), (23), AUTO-BW
@@ -764,19 +766,12 @@
(2402 - 2482 @ 40), (20)
(5170 - 5250 @ 80), (20), AUTO-BW
(5250 - 5330 @ 80), (20), DFS, AUTO-BW
- (5490 - 5710 @ 160), (30), DFS
+ (5490 - 5730 @ 160), (30), DFS
(5735 - 5835 @ 80), (30)
# 60 GHz band channels 1-4,
# ref: http://www.law.go.kr/%ED%96%89%EC%A0%95%EA%B7%9C%EC%B9%99/%EB%AC%B4%EC%84%A0%EC%84%A4%EB%B9%84%EA%B7%9C%EC%B9%99
(57240 - 65880 @ 2160), (43)
-country KP: DFS-ETSI
- (2402 - 2482 @ 40), (20)
- (5170 - 5250 @ 80), (20)
- (5250 - 5330 @ 80), (20), DFS
- (5490 - 5630 @ 80), (30), DFS
- (5735 - 5815 @ 80), (30)
-
country KW: DFS-ETSI
(2402 - 2482 @ 40), (20)
(5170 - 5250 @ 80), (23), AUTO-BW
@@ -1022,7 +1017,7 @@
(2402 - 2482 @ 40), (20)
(5170 - 5250 @ 80), (23), AUTO-BW
(5250 - 5330 @ 80), (23), DFS, AUTO-BW
- (5490 - 5710 @ 160), (30), DFS
+ (5490 - 5730 @ 160), (30), DFS
(5735 - 5835 @ 80), (33)
country NG: DFS-ETSI
@@ -1338,9 +1333,6 @@
(5250 - 5330 @ 20), (23), DFS
(5735 - 5835 @ 20), (30)
-country SY:
- (2402 - 2482 @ 40), (20)
-
country TC: DFS-FCC
(2402 - 2482 @ 40), (20)
(5170 - 5250 @ 80), (24), AUTO-BW
@@ -1426,7 +1418,7 @@
country US: DFS-FCC
(2402 - 2472 @ 40), (30)
- (5170 - 5250 @ 80), (24), AUTO-BW
+ (5170 - 5250 @ 80), (30), AUTO-BW
(5250 - 5330 @ 80), (24), DFS, AUTO-BW
(5490 - 5730 @ 160), (24), DFS
(5735 - 5835 @ 80), (30)
@@ -1467,7 +1459,7 @@
(5490 - 5710 @ 160), (30), DFS
country VE: DFS-FCC
- (2402 - 2482 @ 40), (30)
+ (2402 - 2482 @ 40), (20)
(5170 - 5250 @ 80), (23), AUTO-BW
(5250 - 5330 @ 80), (23), DFS, AUTO-BW
(5735 - 5835 @ 80), (30)
diff --git a/security/Kconfig b/security/Kconfig
index 59aea7d..d11fde4 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -40,6 +40,11 @@
If you are unsure how to answer this question, answer N.
+config SECURITY_WRITABLE_HOOKS
+ depends on SECURITY
+ bool
+ default n
+
config SECURITYFS
bool "Enable the securityfs filesystem"
help
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 41b8cb1..57bc405 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -584,7 +584,7 @@
return error;
}
-static struct security_hook_list apparmor_hooks[] = {
+static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check),
LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme),
LSM_HOOK_INIT(capget, apparmor_capget),
diff --git a/security/commoncap.c b/security/commoncap.c
index a8e4aac..3e44d01 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -1081,7 +1081,7 @@
#ifdef CONFIG_SECURITY
-struct security_hook_list capability_hooks[] = {
+struct security_hook_list capability_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(capable, cap_capable),
LSM_HOOK_INIT(settime, cap_settime),
LSM_HOOK_INIT(ptrace_access_check, cap_ptrace_access_check),
diff --git a/security/loadpin/loadpin.c b/security/loadpin/loadpin.c
index 89a46f1..afd4ab9 100644
--- a/security/loadpin/loadpin.c
+++ b/security/loadpin/loadpin.c
@@ -174,7 +174,7 @@
return 0;
}
-static struct security_hook_list loadpin_hooks[] = {
+static struct security_hook_list loadpin_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(sb_free_security, loadpin_sb_free_security),
LSM_HOOK_INIT(kernel_read_file, loadpin_read_file),
};
diff --git a/security/security.c b/security/security.c
index 1ba5274..6a7b359 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1590,7 +1590,7 @@
}
#endif /* CONFIG_AUDIT */
-struct security_hook_heads security_hook_heads = {
+struct security_hook_heads security_hook_heads __lsm_ro_after_init = {
.binder_set_context_mgr =
LIST_HEAD_INIT(security_hook_heads.binder_set_context_mgr),
.binder_transaction =
diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig
index ea7e3ef..8af7a69 100644
--- a/security/selinux/Kconfig
+++ b/security/selinux/Kconfig
@@ -40,6 +40,7 @@
config SECURITY_SELINUX_DISABLE
bool "NSA SELinux runtime disable"
depends on SECURITY_SELINUX
+ select SECURITY_WRITABLE_HOOKS
default n
help
This option enables writing to a selinuxfs node 'disable', which
@@ -50,6 +51,11 @@
portability across platforms where boot parameters are difficult
to employ.
+ NOTE: selecting this option will disable the '__ro_after_init'
+ kernel hardening feature for security hooks. Please consider
+ using the selinux=0 boot parameter instead of enabling this
+ option.
+
If you are unsure how to answer this question, answer N.
config SECURITY_SELINUX_DEVELOP
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 20b2e7d..e26ecb0 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -6079,7 +6079,7 @@
#endif
-static struct security_hook_list selinux_hooks[] = {
+static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr),
LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction),
LSM_HOOK_INIT(binder_transfer_binder, selinux_binder_transfer_binder),
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 1cb0602..b75c31a 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -4611,7 +4611,7 @@
return 0;
}
-static struct security_hook_list smack_hooks[] = {
+static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(ptrace_access_check, smack_ptrace_access_check),
LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme),
LSM_HOOK_INIT(syslog, smack_syslog),
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
index 75c9987..f1dce33 100644
--- a/security/tomoyo/tomoyo.c
+++ b/security/tomoyo/tomoyo.c
@@ -496,7 +496,7 @@
* tomoyo_security_ops is a "struct security_operations" which is used for
* registering TOMOYO.
*/
-static struct security_hook_list tomoyo_hooks[] = {
+static struct security_hook_list tomoyo_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(cred_alloc_blank, tomoyo_cred_alloc_blank),
LSM_HOOK_INIT(cred_prepare, tomoyo_cred_prepare),
LSM_HOOK_INIT(cred_transfer, tomoyo_cred_transfer),
diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c
index 0309f21..70aa64c 100644
--- a/security/yama/yama_lsm.c
+++ b/security/yama/yama_lsm.c
@@ -414,7 +414,7 @@
return rc;
}
-static struct security_hook_list yama_hooks[] = {
+static struct security_hook_list yama_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(ptrace_access_check, yama_ptrace_access_check),
LSM_HOOK_INIT(ptrace_traceme, yama_ptrace_traceme),
LSM_HOOK_INIT(task_prctl, yama_task_prctl),
diff --git a/sound/soc/codecs/wcd-dsp-mgr.c b/sound/soc/codecs/wcd-dsp-mgr.c
index a6d46ae..6cc9f8c 100644
--- a/sound/soc/codecs/wcd-dsp-mgr.c
+++ b/sound/soc/codecs/wcd-dsp-mgr.c
@@ -417,22 +417,23 @@
/* Go through the list of segments and download one by one */
list_for_each_entry(seg, wdsp->seg_list, list) {
ret = wdsp_load_each_segment(wdsp, seg);
- if (ret < 0) {
- wdsp_broadcast_event_downseq(wdsp,
- WDSP_EVENT_DLOAD_FAILED,
- NULL);
+ if (ret)
goto dload_error;
- }
}
+ /* Flush the list before setting status and notifying components */
+ wdsp_flush_segment_list(wdsp->seg_list);
+
WDSP_SET_STATUS(wdsp, status);
/* Notify all components that image is downloaded */
wdsp_broadcast_event_downseq(wdsp, post, NULL);
+done:
+ return ret;
dload_error:
wdsp_flush_segment_list(wdsp->seg_list);
-done:
+ wdsp_broadcast_event_downseq(wdsp, WDSP_EVENT_DLOAD_FAILED, NULL);
return ret;
}
@@ -486,10 +487,14 @@
/* Make sure wdsp is in good state */
if (!WDSP_STATUS_IS_SET(wdsp, WDSP_STATUS_CODE_DLOADED)) {
WDSP_ERR(wdsp, "WDSP in invalid state 0x%x", wdsp->status);
- ret = -EINVAL;
- goto done;
+ return -EINVAL;
}
+ /*
+ * Acquire SSR mutex lock to make sure enablement of DSP
+ * does not race with SSR handling.
+ */
+ WDSP_MGR_MUTEX_LOCK(wdsp, wdsp->ssr_mutex);
/* Download the read-write sections of image */
ret = wdsp_download_segments(wdsp, WDSP_ELF_FLAG_WRITE);
if (ret < 0) {
@@ -510,6 +515,7 @@
wdsp_broadcast_event_downseq(wdsp, WDSP_EVENT_POST_BOOTUP, NULL);
WDSP_SET_STATUS(wdsp, WDSP_STATUS_BOOTED);
done:
+ WDSP_MGR_MUTEX_UNLOCK(wdsp, wdsp->ssr_mutex);
return ret;
}
diff --git a/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.c b/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.c
index 8da0425..b62f26c 100644
--- a/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.c
+++ b/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.c
@@ -763,10 +763,6 @@
case WDSP_EVENT_DLOAD_FAILED:
case WDSP_EVENT_POST_SHUTDOWN:
- if (event == WDSP_EVENT_POST_DLOAD_CODE)
- /* Mark DSP online since code download is complete */
- wcd_cntl_change_online_state(cntl, 1);
-
/* Disable CPAR */
wcd_cntl_cpar_ctrl(cntl, false);
/* Disable all the clocks */
@@ -775,6 +771,10 @@
dev_err(codec->dev,
"%s: Failed to disable clocks, err = %d\n",
__func__, ret);
+
+ if (event == WDSP_EVENT_POST_DLOAD_CODE)
+ /* Mark DSP online since code download is complete */
+ wcd_cntl_change_online_state(cntl, 1);
break;
case WDSP_EVENT_PRE_DLOAD_DATA:
diff --git a/sound/soc/codecs/wsa881x.h b/sound/soc/codecs/wsa881x.h
index be234ac..fbc60d8 100644
--- a/sound/soc/codecs/wsa881x.h
+++ b/sound/soc/codecs/wsa881x.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
@@ -20,9 +20,10 @@
#define WSA881X_MAX_SWR_PORTS 4
+#if IS_ENABLED(CONFIG_SND_SOC_WSA881X)
extern int wsa881x_set_channel_map(struct snd_soc_codec *codec, u8 *port,
- u8 num_port, unsigned int *ch_mask,
- unsigned int *ch_rate);
+ u8 num_port, unsigned int *ch_mask,
+ unsigned int *ch_rate);
extern const u8 wsa881x_reg_readable[WSA881X_CACHE_SIZE];
extern struct regmap_config wsa881x_regmap_config;
@@ -31,4 +32,25 @@
struct snd_soc_codec *codec);
void wsa881x_regmap_defaults(struct regmap *regmap, u8 version);
+#else
+extern int wsa881x_set_channel_map(struct snd_soc_codec *codec, u8 *port,
+ u8 num_port, unsigned int *ch_mask,
+ unsigned int *ch_rate)
+{
+ return 0;
+}
+
+extern int wsa881x_codec_info_create_codec_entry(
+ struct snd_info_entry *codec_root,
+ struct snd_soc_codec *codec)
+{
+ return 0;
+}
+
+void wsa881x_regmap_defaults(struct regmap *regmap, u8 version)
+{
+}
+
+#endif
+
#endif /* _WSA881X_H */
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 30a4d59..89a9cc2 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -2376,8 +2376,20 @@
.rate_min = 8000,
.rate_max = 384000,
},
+ .capture = {
+ .stream_name = "MultiMedia10 Capture",
+ .aif_name = "MM_UL10",
+ .rates = (SNDRV_PCM_RATE_8000_48000 |
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
.ops = &msm_fe_Multimedia_dai_ops,
- .compress_new = snd_soc_new_compress,
.name = "MultiMedia10",
.probe = fe_dai_probe,
},
diff --git a/sound/soc/msm/msm8998.c b/sound/soc/msm/msm8998.c
index 174db28..05b7d30 100644
--- a/sound/soc/msm/msm8998.c
+++ b/sound/soc/msm/msm8998.c
@@ -5036,12 +5036,13 @@
.id = MSM_FRONTEND_DAI_MULTIMEDIA7,
},
{
- .name = MSM_DAILINK_NAME(Compress3),
- .stream_name = "Compress3",
+ .name = MSM_DAILINK_NAME(MultiMedia10),
+ .stream_name = "MultiMedia10",
.cpu_dai_name = "MultiMedia10",
- .platform_name = "msm-compress-dsp",
+ .platform_name = "msm-pcm-dsp.1",
.dynamic = 1,
.dpcm_playback = 1,
+ .dpcm_capture = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
.codec_dai_name = "snd-soc-dummy-dai",
diff --git a/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.c
index 9f08222..9b845ee 100644
--- a/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.c
@@ -154,7 +154,7 @@
MAX_INBAND_PARAM_SZ,
"VIRT ENABLE", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_VIRTUALIZER;
*updt_params++ =
@@ -182,7 +182,7 @@
MAX_INBAND_PARAM_SZ,
"VIRT STRENGTH", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_VIRTUALIZER;
*updt_params++ =
@@ -210,7 +210,7 @@
MAX_INBAND_PARAM_SZ,
"VIRT OUT_TYPE", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_VIRTUALIZER;
*updt_params++ =
@@ -238,7 +238,7 @@
MAX_INBAND_PARAM_SZ,
"VIRT GAIN_ADJUST", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_VIRTUALIZER;
*updt_params++ =
@@ -316,7 +316,7 @@
MAX_INBAND_PARAM_SZ,
"REVERB_ENABLE", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_REVERB;
*updt_params++ =
@@ -344,7 +344,7 @@
MAX_INBAND_PARAM_SZ,
"REVERB_MODE", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_REVERB;
*updt_params++ =
@@ -372,7 +372,7 @@
MAX_INBAND_PARAM_SZ,
"REVERB_PRESET", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_REVERB;
*updt_params++ =
@@ -400,7 +400,7 @@
MAX_INBAND_PARAM_SZ,
"REVERB_WET_MIX", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_REVERB;
*updt_params++ =
@@ -428,7 +428,7 @@
MAX_INBAND_PARAM_SZ,
"REVERB_GAIN_ADJUST", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_REVERB;
*updt_params++ =
@@ -456,7 +456,7 @@
MAX_INBAND_PARAM_SZ,
"REVERB_ROOM_LEVEL", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_REVERB;
*updt_params++ =
@@ -484,7 +484,7 @@
MAX_INBAND_PARAM_SZ,
"REVERB_ROOM_HF_LEVEL", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_REVERB;
*updt_params++ =
@@ -512,7 +512,7 @@
MAX_INBAND_PARAM_SZ,
"REVERB_DECAY_TIME", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_REVERB;
*updt_params++ =
@@ -540,7 +540,7 @@
MAX_INBAND_PARAM_SZ,
"REVERB_DECAY_HF_RATIO", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_REVERB;
*updt_params++ =
@@ -568,7 +568,7 @@
MAX_INBAND_PARAM_SZ,
"REVERB_REFLECTIONS_LEVEL", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_REVERB;
*updt_params++ =
@@ -596,7 +596,7 @@
MAX_INBAND_PARAM_SZ,
"REVERB_REFLECTIONS_DELAY", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_REVERB;
*updt_params++ =
@@ -624,7 +624,7 @@
MAX_INBAND_PARAM_SZ,
"REVERB_LEVEL", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_REVERB;
*updt_params++ =
@@ -652,7 +652,7 @@
MAX_INBAND_PARAM_SZ,
"REVERB_DELAY", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_REVERB;
*updt_params++ =
@@ -680,7 +680,7 @@
MAX_INBAND_PARAM_SZ,
"REVERB_DIFFUSION", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_REVERB;
*updt_params++ =
@@ -708,7 +708,7 @@
MAX_INBAND_PARAM_SZ,
"REVERB_DENSITY", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_REVERB;
*updt_params++ =
@@ -787,7 +787,7 @@
MAX_INBAND_PARAM_SZ,
"BASS_BOOST_ENABLE", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_BASS_BOOST;
*updt_params++ =
@@ -815,7 +815,7 @@
MAX_INBAND_PARAM_SZ,
"BASS_BOOST_MODE", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_BASS_BOOST;
*updt_params++ =
@@ -843,7 +843,7 @@
MAX_INBAND_PARAM_SZ,
"BASS_BOOST_STRENGTH", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_BASS_BOOST;
*updt_params++ =
@@ -920,7 +920,7 @@
MAX_INBAND_PARAM_SZ,
"PBE_ENABLE", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_PBE;
*updt_params++ =
@@ -946,7 +946,7 @@
MAX_INBAND_PARAM_SZ,
"PBE_PARAM", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_PBE;
*updt_params++ =
@@ -1031,7 +1031,7 @@
MAX_INBAND_PARAM_SZ,
"EQ_ENABLE", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_POPLESS_EQUALIZER;
*updt_params++ =
@@ -1099,7 +1099,7 @@
MAX_INBAND_PARAM_SZ,
"EQ_CONFIG", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_POPLESS_EQUALIZER;
*updt_params++ =
@@ -1150,7 +1150,7 @@
MAX_INBAND_PARAM_SZ,
"EQ_BAND_INDEX", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_POPLESS_EQUALIZER;
*updt_params++ =
@@ -1182,7 +1182,7 @@
MAX_INBAND_PARAM_SZ,
"EQ_SINGLE_BAND_FREQ", rc);
if (rc != 0)
- break;
+ goto invalid_config;
*updt_params++ =
AUDPROC_MODULE_ID_POPLESS_EQUALIZER;
*updt_params++ =
@@ -1271,7 +1271,7 @@
"VOLUME/VOLUME2_GAIN_2CH",
rc);
if (rc != 0)
- break;
+ goto invalid_config;
if (instance == SOFT_VOLUME_INSTANCE_2)
*updt_params++ =
ASM_MODULE_ID_VOL_CTRL2;
@@ -1320,7 +1320,7 @@
"VOLUME/VOLUME2_GAIN_MASTER",
rc);
if (rc != 0)
- break;
+ goto invalid_config;
if (instance == SOFT_VOLUME_INSTANCE_2)
*updt_params++ =
ASM_MODULE_ID_VOL_CTRL2;
diff --git a/sound/soc/msm/qdsp6v2/msm-lsm-client.c b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
index 3a6cbe6..ef3475c 100644
--- a/sound/soc/msm/qdsp6v2/msm-lsm-client.c
+++ b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
@@ -1682,7 +1682,7 @@
dev_err(rtd->dev,
"%s REG_SND_MODEL failed err %d\n",
__func__, err);
- return err;
+ goto done;
}
break;
case SNDRV_LSM_SET_PARAMS: {
@@ -1852,13 +1852,15 @@
dev_err(rtd->dev,
"%s: Invalid params event_status_v3\n",
__func__);
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
if (copy_from_user(&userarg, arg, sizeof(userarg))) {
dev_err(rtd->dev,
"%s: err copyuser event_status_v3\n",
__func__);
- return -EFAULT;
+ err = -EFAULT;
+ goto done;
}
if (userarg.payload_size >
@@ -1866,7 +1868,8 @@
pr_err("%s: payload_size %d is invalid, max allowed = %d\n",
__func__, userarg.payload_size,
LISTEN_MAX_STATUS_PAYLOAD_SIZE);
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
size = sizeof(struct snd_lsm_event_status_v3) +
@@ -1876,7 +1879,8 @@
dev_err(rtd->dev,
"%s: Allocation failed event status size %d\n",
__func__, size);
- return -EFAULT;
+ err = -EFAULT;
+ goto done;
}
user->payload_size = userarg.payload_size;
err = msm_lsm_ioctl_shared(substream, cmd, user);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index ef50d92..5948bbf 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -3645,6 +3645,11 @@
msm_route_ec_ref_rx_enum[0],
msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put);
+static const struct snd_kcontrol_new ext_ec_ref_mux_ul10 =
+ SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL10 MUX Mux",
+ msm_route_ec_ref_rx_enum[0],
+ msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put);
+
static const struct snd_kcontrol_new ext_ec_ref_mux_ul17 =
SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL17 MUX Mux",
msm_route_ec_ref_rx_enum[0],
@@ -7251,6 +7256,59 @@
msm_routing_put_audio_mixer),
};
+static const struct snd_kcontrol_new mmul10_mixer_controls[] = {
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SLIM_6_TX", MSM_BACKEND_DAI_SLIMBUS_6_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("USB_AUDIO_TX", MSM_BACKEND_DAI_USB_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
static const struct snd_kcontrol_new mmul17_mixer_controls[] = {
SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
@@ -11489,6 +11547,7 @@
SND_SOC_DAPM_AIF_OUT("MM_UL6", "MultiMedia6 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL8", "MultiMedia8 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL9", "MultiMedia9 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("MM_UL10", "MultiMedia10 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL16", "MultiMedia16 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL17", "MultiMedia17 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL18", "MultiMedia18 Capture", 0, 0, 0, 0),
@@ -12225,6 +12284,8 @@
mmul8_mixer_controls, ARRAY_SIZE(mmul8_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia9 Mixer", SND_SOC_NOPM, 0, 0,
mmul9_mixer_controls, ARRAY_SIZE(mmul9_mixer_controls)),
+ SND_SOC_DAPM_MIXER("MultiMedia10 Mixer", SND_SOC_NOPM, 0, 0,
+ mmul10_mixer_controls, ARRAY_SIZE(mmul10_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia16 Mixer", SND_SOC_NOPM, 0, 0,
mmul16_mixer_controls, ARRAY_SIZE(mmul16_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia17 Mixer", SND_SOC_NOPM, 0, 0,
@@ -12557,6 +12618,8 @@
&ext_ec_ref_mux_ul8),
SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL9 MUX", SND_SOC_NOPM, 0, 0,
&ext_ec_ref_mux_ul9),
+ SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL10 MUX", SND_SOC_NOPM, 0, 0,
+ &ext_ec_ref_mux_ul10),
SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL16 MUX", SND_SOC_NOPM, 0, 0,
&ext_ec_ref_mux_ul16),
SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL17 MUX", SND_SOC_NOPM, 0, 0,
@@ -12810,9 +12873,11 @@
{"MultiMedia8 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
{"MultiMedia3 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia5 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+ {"MultiMedia10 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia16 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia5 Mixer", "SLIM_7_TX", "SLIMBUS_7_TX"},
{"MultiMedia5 Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"},
+ {"MultiMedia10 Mixer", "SLIM_7_TX", "SLIMBUS_7_TX"},
{"MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
@@ -13379,6 +13444,7 @@
{"MultiMedia2 Mixer", "MI2S_TX", "MI2S_TX"},
{"MultiMedia3 Mixer", "MI2S_TX", "MI2S_TX"},
{"MultiMedia5 Mixer", "MI2S_TX", "MI2S_TX"},
+ {"MultiMedia10 Mixer", "MI2S_TX", "MI2S_TX"},
{"MultiMedia16 Mixer", "MI2S_TX", "MI2S_TX"},
{"MultiMedia1 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
{"MultiMedia2 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
@@ -13395,17 +13461,21 @@
{"MultiMedia1 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
{"MultiMedia3 Mixer", "AUX_PCM_TX", "AUX_PCM_TX"},
{"MultiMedia5 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+ {"MultiMedia10 Mixer", "AUX_PCM_TX", "AUX_PCM_TX"},
{"MultiMedia1 Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
{"MultiMedia3 Mixer", "SEC_AUX_PCM_TX", "SEC_AUX_PCM_TX"},
{"MultiMedia5 Mixer", "SEC_AUX_PCM_TX", "SEC_AUX_PCM_TX"},
+ {"MultiMedia10 Mixer", "SEC_AUX_PCM_TX", "SEC_AUX_PCM_TX"},
{"MultiMedia16 Mixer", "AUX_PCM_TX", "AUX_PCM_TX"},
{"MultiMedia16 Mixer", "SEC_AUX_PCM_TX", "SEC_AUX_PCM_TX"},
{"MultiMedia1 Mixer", "TERT_AUXPCM_UL_TX", "TERT_AUX_PCM_TX"},
{"MultiMedia3 Mixer", "TERT_AUX_PCM_TX", "TERT_AUX_PCM_TX"},
{"MultiMedia5 Mixer", "TERT_AUX_PCM_TX", "TERT_AUX_PCM_TX"},
+ {"MultiMedia10 Mixer", "TERT_AUX_PCM_TX", "TERT_AUX_PCM_TX"},
{"MultiMedia1 Mixer", "QUAT_AUXPCM_UL_TX", "QUAT_AUX_PCM_TX"},
{"MultiMedia3 Mixer", "QUAT_AUX_PCM_TX", "QUAT_AUX_PCM_TX"},
{"MultiMedia5 Mixer", "QUAT_AUX_PCM_TX", "QUAT_AUX_PCM_TX"},
+ {"MultiMedia10 Mixer", "QUAT_AUX_PCM_TX", "QUAT_AUX_PCM_TX"},
{"MultiMedia16 Mixer", "QUAT_AUX_PCM_TX", "QUAT_AUX_PCM_TX"},
{"MultiMedia2 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia2 Mixer", "SLIM_6_TX", "SLIMBUS_6_TX"},
@@ -13418,13 +13488,16 @@
{"MultiMedia6 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
{"MultiMedia3 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
{"MultiMedia5 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"MultiMedia10 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
{"MultiMedia6 Mixer", "INT2_MI2S_TX", "INT2_MI2S_TX"},
{"MultiMedia3 Mixer", "INT2_MI2S_TX", "INT2_MI2S_TX"},
{"MultiMedia5 Mixer", "INT2_MI2S_TX", "INT2_MI2S_TX"},
+ {"MultiMedia10 Mixer", "INT2_MI2S_TX", "INT2_MI2S_TX"},
{"MultiMedia16 Mixer", "INT2_MI2S_TX", "INT2_MI2S_TX"},
{"MultiMedia6 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
{"MultiMedia3 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
{"MultiMedia5 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
+ {"MultiMedia10 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
{"MultiMedia16 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
{"MultiMedia6 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
{"MultiMedia6 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
@@ -13559,6 +13632,14 @@
{"MultiMedia9 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
{"MultiMedia9 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+ {"MultiMedia10 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
+ {"MultiMedia10 Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"},
+ {"MultiMedia10 Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"},
+ {"MultiMedia10 Mixer", "TERT_TDM_TX_3", "TERT_TDM_TX_3"},
+ {"MultiMedia10 Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+ {"MultiMedia10 Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+ {"MultiMedia10 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+ {"MultiMedia10 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
{"MultiMedia20 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
{"MultiMedia20 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
{"MultiMedia20 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
@@ -13586,6 +13667,7 @@
{"MultiMedia5 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"},
{"MultiMedia6 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"},
{"MultiMedia8 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"},
+ {"MultiMedia10 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"},
{"MultiMedia16 Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"},
{"MultiMedia16 Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"},
@@ -13682,6 +13764,7 @@
{"MultiMedia1 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"MultiMedia3 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"MultiMedia4 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"MultiMedia10 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"MultiMedia17 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"MultiMedia18 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"MultiMedia19 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
@@ -13701,6 +13784,7 @@
{"MultiMedia1 Mixer", "AFE_PCM_TX", "PCM_TX"},
{"MultiMedia3 Mixer", "AFE_PCM_TX", "PCM_TX"},
{"MultiMedia4 Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"MultiMedia10 Mixer", "AFE_PCM_TX", "PCM_TX"},
{"MultiMedia17 Mixer", "AFE_PCM_TX", "PCM_TX"},
{"MultiMedia18 Mixer", "AFE_PCM_TX", "PCM_TX"},
{"MultiMedia19 Mixer", "AFE_PCM_TX", "PCM_TX"},
@@ -13716,6 +13800,7 @@
{"MM_UL6", NULL, "MultiMedia6 Mixer"},
{"MM_UL8", NULL, "MultiMedia8 Mixer"},
{"MM_UL9", NULL, "MultiMedia9 Mixer"},
+ {"MM_UL10", NULL, "MultiMedia10 Mixer"},
{"MM_UL16", NULL, "MultiMedia16 Mixer"},
{"MM_UL17", NULL, "MultiMedia17 Mixer"},
{"MM_UL18", NULL, "MultiMedia18 Mixer"},
@@ -14104,6 +14189,16 @@
{"AUDIO_REF_EC_UL9 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"},
{"AUDIO_REF_EC_UL9 MUX", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL10 MUX", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"AUDIO_REF_EC_UL10 MUX", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"AUDIO_REF_EC_UL10 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL10 MUX", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL10 MUX", "SLIM_1_TX", "SLIMBUS_1_TX"},
+ {"AUDIO_REF_EC_UL10 MUX", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+ {"AUDIO_REF_EC_UL10 MUX", "QUAT_TDM_RX_0", "QUAT_TDM_RX_0"},
+ {"AUDIO_REF_EC_UL10 MUX", "QUAT_TDM_RX_1", "QUAT_TDM_RX_1"},
+ {"AUDIO_REF_EC_UL10 MUX", "QUAT_TDM_RX_2", "QUAT_TDM_RX_2"},
+ {"AUDIO_REF_EC_UL10 MUX", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
{"AUDIO_REF_EC_UL17 MUX", "PRI_MI2S_TX", "PRI_MI2S_TX"},
{"AUDIO_REF_EC_UL17 MUX", "SEC_MI2S_TX", "SEC_MI2S_TX"},
{"AUDIO_REF_EC_UL17 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"},
@@ -14127,6 +14222,7 @@
{"MM_UL6", NULL, "AUDIO_REF_EC_UL6 MUX"},
{"MM_UL8", NULL, "AUDIO_REF_EC_UL8 MUX"},
{"MM_UL9", NULL, "AUDIO_REF_EC_UL9 MUX"},
+ {"MM_UL10", NULL, "AUDIO_REF_EC_UL10 MUX"},
{"MM_UL16", NULL, "AUDIO_REF_EC_UL16 MUX"},
{"MM_UL17", NULL, "AUDIO_REF_EC_UL17 MUX"},
{"MM_UL18", NULL, "AUDIO_REF_EC_UL18 MUX"},
diff --git a/sound/soc/msm/qdsp6v2/q6core.c b/sound/soc/msm/qdsp6v2/q6core.c
index 3aaaa35..4c3a3a1 100644
--- a/sound/soc/msm/qdsp6v2/q6core.c
+++ b/sound/soc/msm/qdsp6v2/q6core.c
@@ -21,6 +21,8 @@
#include <linux/qdsp6v2/apr.h>
#include <sound/q6core.h>
#include <sound/audio_cal_utils.h>
+#include <sound/adsp_err.h>
+#include <sound/apr_audio-v2.h>
#define TIMEOUT_MS 1000
/*
@@ -36,16 +38,30 @@
CORE_MAX_CAL
};
+enum ver_query_status {
+ VER_QUERY_UNATTEMPTED,
+ VER_QUERY_UNSUPPORTED,
+ VER_QUERY_SUPPORTED
+};
+
+struct q6core_avcs_ver_info {
+ enum ver_query_status status;
+ struct avcs_fwk_ver_info ver_info;
+};
+
struct q6core_str {
struct apr_svc *core_handle_q;
wait_queue_head_t bus_bw_req_wait;
wait_queue_head_t cmd_req_wait;
+ wait_queue_head_t avcs_fwk_ver_req_wait;
u32 bus_bw_resp_received;
enum cmd_flags {
FLAG_NONE,
FLAG_CMDRSP_LICENSE_RESULT
} cmd_resp_received_flag;
+ u32 avcs_fwk_ver_resp_received;
struct mutex cmd_lock;
+ struct mutex ver_lock;
union {
struct avcs_cmdrsp_get_license_validation_result
cmdrsp_license_result;
@@ -54,6 +70,7 @@
struct cal_type_data *cal_data[CORE_MAX_CAL];
uint32_t mem_map_cal_handle;
int32_t adsp_status;
+ struct q6core_avcs_ver_info q6core_avcs_ver_info;
};
static struct q6core_str q6core_lcl;
@@ -65,9 +82,61 @@
};
static struct generic_get_data_ *generic_get_data;
+static int parse_fwk_version_info(uint32_t *payload)
+{
+ size_t fwk_ver_size;
+ size_t svc_size;
+ int num_services;
+ int ret = 0;
+
+ pr_debug("%s: Payload info num services %d\n",
+ __func__, payload[4]);
+ /*
+ * payload1[4] is the number of services running on DSP
+ * Based on this info, we copy the payload into core
+ * avcs version info structure.
+ */
+ num_services = payload[4];
+ q6core_lcl.q6core_avcs_ver_info.ver_info.avcs_fwk_version.
+ num_services = num_services;
+ if (num_services > VSS_MAX_AVCS_NUM_SERVICES) {
+ pr_err("%s: num_services: %d greater than max services: %d\n",
+ __func__, num_services, VSS_MAX_AVCS_NUM_SERVICES);
+ ret = -EINVAL;
+ goto done;
+ }
+ fwk_ver_size = sizeof(struct avcs_get_fwk_version);
+ svc_size = num_services * sizeof(struct avs_svc_api_info);
+ /*
+ * Dynamically allocate memory for all
+ * the services based on num_services
+ */
+ q6core_lcl.q6core_avcs_ver_info.ver_info.services = NULL;
+ q6core_lcl.q6core_avcs_ver_info.ver_info.services =
+ kzalloc(svc_size, GFP_ATOMIC);
+ if (q6core_lcl.q6core_avcs_ver_info.ver_info.services == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ /*
+ * memcpy is done twice because the memory allocated for
+ * q6core_lcl.q6core_avcs_ver_info.ver_info is not
+ * contiguous.
+ */
+ memcpy(&q6core_lcl.q6core_avcs_ver_info.ver_info,
+ (uint8_t *)payload, fwk_ver_size);
+ memcpy(q6core_lcl.q6core_avcs_ver_info.ver_info.services,
+ (uint8_t *)&payload[sizeof(struct avcs_get_fwk_version)/
+ sizeof(uint32_t)], svc_size);
+ ret = 0;
+done:
+ return ret;
+}
+
static int32_t aprv2_core_fn_q(struct apr_client_data *data, void *priv)
{
uint32_t *payload1;
+ int ret = 0;
if (data == NULL) {
pr_err("%s: data argument is null\n", __func__);
@@ -118,6 +187,17 @@
q6core_lcl.bus_bw_resp_received = 1;
wake_up(&q6core_lcl.bus_bw_req_wait);
break;
+ case AVCS_CMD_GET_FWK_VERSION:
+ pr_debug("%s: Cmd = AVCS_CMD_GET_FWK_VERSION status[%s]\n",
+ __func__, adsp_err_get_err_str(payload1[1]));
+ /* ADSP status to match Linux error standard */
+ q6core_lcl.adsp_status = -payload1[1];
+ if (payload1[1] == ADSP_EUNSUPPORTED)
+ q6core_lcl.q6core_avcs_ver_info.status =
+ VER_QUERY_UNSUPPORTED;
+ q6core_lcl.avcs_fwk_ver_resp_received = 1;
+ wake_up(&q6core_lcl.avcs_fwk_ver_req_wait);
+ break;
default:
pr_err("%s: Invalid cmd rsp[0x%x][0x%x] opcode %d\n",
__func__,
@@ -130,7 +210,7 @@
case RESET_EVENTS:{
pr_debug("%s: Reset event received in Core service\n",
__func__);
- apr_reset(q6core_lcl.core_handle_q);
+ /* no reset done as the data will not change after SSR*/
q6core_lcl.core_handle_q = NULL;
break;
}
@@ -161,6 +241,18 @@
q6core_lcl.cmd_resp_received_flag = FLAG_CMDRSP_LICENSE_RESULT;
wake_up(&q6core_lcl.cmd_req_wait);
break;
+ case AVCS_CMDRSP_GET_FWK_VERSION:
+ pr_debug("%s: Received AVCS_CMDRSP_GET_FWK_VERSION\n",
+ __func__);
+ payload1 = data->payload;
+ q6core_lcl.q6core_avcs_ver_info.status = VER_QUERY_SUPPORTED;
+ q6core_lcl.avcs_fwk_ver_resp_received = 1;
+ ret = parse_fwk_version_info(payload1);
+ if (ret < 0)
+ pr_err("%s: Failed to parse payload:%d\n",
+ __func__, ret);
+ wake_up(&q6core_lcl.avcs_fwk_ver_req_wait);
+ break;
default:
pr_err("%s: Message id from adsp core svc: 0x%x\n",
__func__, data->opcode);
@@ -217,6 +309,157 @@
return NULL;
}
+static int q6core_send_get_avcs_fwk_ver_cmd(void)
+{
+ struct apr_hdr avcs_ver_cmd;
+ int ret;
+
+ avcs_ver_cmd.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ avcs_ver_cmd.pkt_size = sizeof(struct apr_hdr);
+ avcs_ver_cmd.src_port = 0;
+ avcs_ver_cmd.dest_port = 0;
+ avcs_ver_cmd.token = 0;
+ avcs_ver_cmd.opcode = AVCS_CMD_GET_FWK_VERSION;
+
+ q6core_lcl.adsp_status = 0;
+ q6core_lcl.avcs_fwk_ver_resp_received = 0;
+
+ ret = apr_send_pkt(q6core_lcl.core_handle_q,
+ (uint32_t *) &avcs_ver_cmd);
+ if (ret < 0) {
+ pr_err("%s: failed to send apr packet, ret=%d\n", __func__,
+ ret);
+ goto done;
+ }
+
+ ret = wait_event_timeout(q6core_lcl.avcs_fwk_ver_req_wait,
+ (q6core_lcl.avcs_fwk_ver_resp_received == 1),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout for AVCS fwk version info\n",
+ __func__);
+ ret = -ETIMEDOUT;
+ goto done;
+ }
+
+ if (q6core_lcl.adsp_status < 0) {
+ /*
+ * adsp_err_get_err_str expects a positive value but we store
+ * the DSP error as negative to match the Linux error standard.
+ * Pass in the negated value so adsp_err_get_err_str returns
+ * the correct string.
+ */
+ pr_err("%s: DSP returned error[%s]\n", __func__,
+ adsp_err_get_err_str(-q6core_lcl.adsp_status));
+ ret = adsp_err_get_lnx_err_code(q6core_lcl.adsp_status);
+ goto done;
+ }
+
+ ret = 0;
+
+done:
+ return ret;
+}
+
+int q6core_get_service_version(uint32_t service_id,
+ struct avcs_fwk_ver_info *ver_info,
+ size_t size)
+{
+ int i;
+ uint32_t num_services;
+ size_t svc_size;
+
+ svc_size = q6core_get_avcs_service_size(service_id);
+ if (svc_size != size) {
+ pr_err("%s: Expected size: %ld, Provided size: %ld",
+ __func__, svc_size, size);
+ return -EINVAL;
+ }
+
+ num_services =
+ q6core_lcl.q6core_avcs_ver_info.ver_info.
+ avcs_fwk_version.num_services;
+
+ if (ver_info == NULL) {
+ pr_err("%s: NULL parameter ver_info\n", __func__);
+ return -EINVAL;
+ }
+
+ memcpy(ver_info, &q6core_lcl.q6core_avcs_ver_info.
+ ver_info.avcs_fwk_version, sizeof(struct avcs_get_fwk_version));
+
+ if (service_id == AVCS_SERVICE_ID_ALL) {
+ memcpy(&ver_info->services[0], &q6core_lcl.
+ q6core_avcs_ver_info.ver_info.services[0],
+ (num_services * sizeof(struct avs_svc_api_info)));
+ } else {
+ for (i = 0; i < num_services; i++) {
+ if (q6core_lcl.q6core_avcs_ver_info.
+ ver_info.services[i].service_id == service_id) {
+ memcpy(&ver_info->services[0],
+ &q6core_lcl.q6core_avcs_ver_info.
+ ver_info.services[i], size);
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(q6core_get_service_version);
+
+size_t q6core_get_avcs_service_size(uint32_t service_id)
+{
+ int ret = 0;
+ uint32_t num_services;
+
+ num_services =
+ q6core_lcl.q6core_avcs_ver_info.ver_info.
+ avcs_fwk_version.num_services;
+
+ mutex_lock(&(q6core_lcl.ver_lock));
+ pr_debug("%s: q6core_avcs_ver_info.status(%d)\n", __func__,
+ q6core_lcl.q6core_avcs_ver_info.status);
+
+ switch (q6core_lcl.q6core_avcs_ver_info.status) {
+ case VER_QUERY_SUPPORTED:
+ pr_debug("%s: AVCS FWK version query already attempted\n",
+ __func__);
+ ret = num_services * sizeof(struct avs_svc_api_info);
+ break;
+ case VER_QUERY_UNSUPPORTED:
+ ret = -EOPNOTSUPP;
+ break;
+ case VER_QUERY_UNATTEMPTED:
+ pr_debug("%s: Attempting AVCS FWK version query\n", __func__);
+ if (q6core_is_adsp_ready()) {
+ ret = q6core_send_get_avcs_fwk_ver_cmd();
+ if (ret == 0)
+ ret = num_services *
+ sizeof(struct avs_svc_api_info);
+ } else {
+ pr_err("%s: ADSP is not ready to query version\n",
+ __func__);
+ ret = -ENODEV;
+ }
+ break;
+ default:
+ pr_err("%s: Invalid version query status %d\n", __func__,
+ q6core_lcl.q6core_avcs_ver_info.status);
+ ret = -EINVAL;
+ break;
+ }
+ mutex_unlock(&(q6core_lcl.ver_lock));
+
+ if (service_id != AVCS_SERVICE_ID_ALL)
+ return sizeof(struct avs_svc_api_info);
+
+ return ret;
+}
+EXPORT_SYMBOL(q6core_get_avcs_service_size);
+
int32_t core_set_license(uint32_t key, uint32_t module_id)
{
struct avcs_cmd_set_license *cmd_setl = NULL;
@@ -827,18 +1070,16 @@
static int __init core_init(void)
{
+ memset(&q6core_lcl, 0, sizeof(struct q6core_str));
init_waitqueue_head(&q6core_lcl.bus_bw_req_wait);
- q6core_lcl.bus_bw_resp_received = 0;
-
- q6core_lcl.core_handle_q = NULL;
-
init_waitqueue_head(&q6core_lcl.cmd_req_wait);
+ init_waitqueue_head(&q6core_lcl.avcs_fwk_ver_req_wait);
q6core_lcl.cmd_resp_received_flag = FLAG_NONE;
mutex_init(&q6core_lcl.cmd_lock);
- q6core_lcl.mem_map_cal_handle = 0;
- q6core_lcl.adsp_status = 0;
+ mutex_init(&q6core_lcl.ver_lock);
q6core_init_cal_data();
+
return 0;
}
module_init(core_init);
@@ -846,6 +1087,7 @@
static void __exit core_exit(void)
{
mutex_destroy(&q6core_lcl.cmd_lock);
+ mutex_destroy(&q6core_lcl.ver_lock);
q6core_delete_cal_data();
}
module_exit(core_exit);
diff --git a/sound/soc/msm/sdm660-ext-dai-links.c b/sound/soc/msm/sdm660-ext-dai-links.c
index 34a6626..68a0f37 100644
--- a/sound/soc/msm/sdm660-ext-dai-links.c
+++ b/sound/soc/msm/sdm660-ext-dai-links.c
@@ -997,13 +997,14 @@
.id = MSM_FRONTEND_DAI_MULTIMEDIA7,
},
{/* hw:x,16 */
- .name = MSM_DAILINK_NAME(Compress3),
- .stream_name = "Compress3",
+ .name = MSM_DAILINK_NAME(MultiMedia10),
+ .stream_name = "MultiMedia10",
.cpu_dai_name = "MultiMedia10",
- .platform_name = "msm-compress-dsp",
+ .platform_name = "msm-pcm-dsp.1",
.dynamic = 1,
.dpcm_capture = 1,
.dpcm_playback = 1,
+ .dpcm_capture = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
.codec_dai_name = "snd-soc-dummy-dai",
diff --git a/sound/soc/msm/sdm660-internal.c b/sound/soc/msm/sdm660-internal.c
index 1402154..14e7308 100644
--- a/sound/soc/msm/sdm660-internal.c
+++ b/sound/soc/msm/sdm660-internal.c
@@ -1915,13 +1915,14 @@
.id = MSM_FRONTEND_DAI_MULTIMEDIA7,
},
{/* hw:x,16 */
- .name = MSM_DAILINK_NAME(Compress3),
- .stream_name = "Compress3",
+ .name = MSM_DAILINK_NAME(MultiMedia10),
+ .stream_name = "MultiMedia10",
.cpu_dai_name = "MultiMedia10",
- .platform_name = "msm-compress-dsp",
+ .platform_name = "msm-pcm-dsp.1",
.dynamic = 1,
.dpcm_capture = 1,
.dpcm_playback = 1,
+ .dpcm_capture = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
.codec_dai_name = "snd-soc-dummy-dai",
diff --git a/sound/soc/msm/sdm845.c b/sound/soc/msm/sdm845.c
index 838771c..7a5ccd8 100644
--- a/sound/soc/msm/sdm845.c
+++ b/sound/soc/msm/sdm845.c
@@ -5126,12 +5126,13 @@
.id = MSM_FRONTEND_DAI_MULTIMEDIA7,
},
{
- .name = MSM_DAILINK_NAME(Compress3),
- .stream_name = "Compress3",
+ .name = MSM_DAILINK_NAME(MultiMedia10),
+ .stream_name = "MultiMedia10",
.cpu_dai_name = "MultiMedia10",
- .platform_name = "msm-compress-dsp",
+ .platform_name = "msm-pcm-dsp.1",
.dynamic = 1,
.dpcm_playback = 1,
+ .dpcm_capture = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
.codec_dai_name = "snd-soc-dummy-dai",
@@ -6696,16 +6697,18 @@
ret = of_property_read_u32(pdev->dev.of_node,
"qcom,wsa-max-devs", &wsa_max_devs);
if (ret) {
- dev_dbg(&pdev->dev,
+ dev_info(&pdev->dev,
"%s: wsa-max-devs property missing in DT %s, ret = %d\n",
__func__, pdev->dev.of_node->full_name, ret);
- goto err;
+ card->num_aux_devs = 0;
+ return 0;
}
if (wsa_max_devs == 0) {
dev_warn(&pdev->dev,
"%s: Max WSA devices is 0 for this target?\n",
__func__);
- goto err;
+ card->num_aux_devs = 0;
+ return 0;
}
/* Get count of WSA device phandles for this platform */