diff options
author | Sravanthi Palakonda <c_srapal@qti.qualcomm.com> | 2019-07-05 21:15:27 +0530 |
---|---|---|
committer | Sravanthi Palakonda <c_srapal@qti.qualcomm.com> | 2019-07-05 21:30:29 +0530 |
commit | d8de8c3c4eded557cab31ad453a5e72d51b59492 (patch) | |
tree | a9ccc3a0efaf4a518075f01652db17f04b1fbdfa | |
parent | c6c452a64ca80dab24e89accdceecf92e604e547 (diff) | |
parent | 2ec8464f5c53930b53c763289e6f6367508b6f16 (diff) |
Merge commit '2ec8464f5c53930b53c763289e6f6367508b6f16' into HEADLA.UM.7.1.r1-15400-sm8150.0LA.UM.7.1.r1-15300-sm8150.0
Change-Id: Id56a431251a26c96de3598360b4933e08f0b2f8d
Signed-off-by: Sravanthi Palakonda <c_srapal@qti.qualcomm.com>
87 files changed, 1715 insertions, 469 deletions
diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt index 5e374fb6a9b1..23c745deaa87 100644 --- a/Documentation/devicetree/bindings/gpu/adreno.txt +++ b/Documentation/devicetree/bindings/gpu/adreno.txt @@ -207,6 +207,10 @@ Optional Properties: Specify the name of GPU temperature sensor. This name will be used to get the temperature from the thermal driver API. +- tzone-names: + Specify the names of GPU thermal zones. These will be used + to get the temperature from the thermal driver API. + - qcom,enable-midframe-timer: Boolean. Enables the use of midframe sampling timer. This timer samples the GPU powerstats if the cmdbatch expiry takes longer than diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie-camera.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie-camera.dtsi index adf4f26ef8c1..0465a97da52a 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie-camera.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2019, 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 @@ -409,10 +409,10 @@ }; iova-mem-region-shared { - /* Shared region is 100MB long */ + /* Shared region is 150MB long */ iova-region-name = "shared"; iova-region-start = <0x7400000>; - iova-region-len = <0x6400000>; + iova-region-len = <0x9600000>; iova-region-id = <0x1>; status = "ok"; }; @@ -420,7 +420,7 @@ iova-mem-region-secondary-heap { /* Secondary heap region is 1MB long */ iova-region-name = "secheap"; - iova-region-start = <0xd800000>; + iova-region-start = <0x10A00000>; iova-region-len = <0x100000>; iova-region-id = <0x4>; status = "ok"; @@ -429,8 +429,8 @@ iova-mem-region-io { /* IO region is approximately 3 GB */ iova-region-name = "io"; - iova-region-start = <0xda00000>; - iova-region-len = <0xace00000>; + iova-region-start = <0x10C00000>; + iova-region-len = <0xA9C00000>; iova-region-id = <0x3>; status = "ok"; }; @@ -438,7 +438,7 @@ iova-mem-qdss-region { /* QDSS region is appropriate 1MB */ iova-region-name = "qdss"; - iova-region-start = <0xd900000>; + iova-region-start = <0x10B00000>; iova-region-len = <0x100000>; iova-region-id = <0x5>; qdss-phy-addr = <0x16790000>; @@ -1076,7 +1076,7 @@ qcom,cam-cx-ipeak = <&cx_ipeak_lm 3>; control-camnoc-axi-clk; camnoc-bus-width = <32>; - camnoc-axi-clk-bw-margin-perc = <10>; + camnoc-axi-clk-bw-margin-perc = <20>; qcom,msm-bus,name = "cam_ahb"; qcom,msm-bus,num-cases = <6>; qcom,msm-bus,num-paths = <1>; diff --git a/arch/arm64/boot/dts/qcom/sm6150-camera.dtsi b/arch/arm64/boot/dts/qcom/sm6150-camera.dtsi index feeb01c194bc..df9bf2c3a626 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-camera.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2019, 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 @@ -318,10 +318,10 @@ }; iova-mem-region-shared { - /* Shared region is 100MB long */ + /* Shared region is 150MB long */ iova-region-name = "shared"; iova-region-start = <0x7400000>; - iova-region-len = <0x6400000>; + iova-region-len = <0x9600000>; iova-region-id = <0x1>; iova-granularity = <0x15>; status = "ok"; @@ -330,7 +330,7 @@ iova-mem-region-secondary-heap { /* Secondary heap region is 1MB long */ iova-region-name = "secheap"; - iova-region-start = <0xd800000>; + iova-region-start = <0x10A00000>; iova-region-len = <0x100000>; iova-region-id = <0x4>; status = "ok"; @@ -339,8 +339,8 @@ iova-mem-region-io { /* IO region is approximately 3 GB */ iova-region-name = "io"; - iova-region-start = <0xd911000>; - iova-region-len = <0xd26ef000>; + iova-region-start = <0x10B11000>; + iova-region-len = <0xCF4EF000>; iova-region-id = <0x3>; status = "ok"; }; @@ -348,7 +348,7 @@ iova-mem-qdss-region { /* qdss region is approximately 64K */ iova-region-name = "qdss"; - iova-region-start = <0xd900000>; + iova-region-start = <0x10B00000>; iova-region-len = <0x10000>; iova-region-id = <0x5>; qdss-phy-addr = <0x16790000>; diff --git a/arch/arm64/boot/dts/qcom/sm6150-sde.dtsi b/arch/arm64/boot/dts/qcom/sm6150-sde.dtsi index 5953edc4219d..d371345fe54c 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-sde.dtsi @@ -527,7 +527,9 @@ qcom,logical2physical-lane-map = [03 02 00 01]; qcom,max-lclk-frequency-khz = <540000>; - qcom,max-pclk-frequency-khz = <195000>; + qcom,max-pclk-frequency-khz = <200000>; + qcom,max-hdisplay = <1920>; + qcom,max-vdisplay = <1200>; qcom,ext-disp = <&ext_disp>; qcom,dp-aux-switch = <&fsa4480>; diff --git a/arch/arm64/boot/dts/qcom/sm8150-coresight.dtsi b/arch/arm64/boot/dts/qcom/sm8150-coresight.dtsi index 812a8e10ed34..075c3e42ffc0 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-coresight.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-coresight.dtsi @@ -635,7 +635,6 @@ ports { #address-cells = <1>; #size-cells = <0>; - port@0 { reg = <0>; funnel_in2_out_funnel_merg: endpoint { @@ -643,7 +642,6 @@ <&funnel_merg_in_funnel_in2>; }; }; - port@1 { reg = <2>; funnel_in2_in_funnel_apss_merg: endpoint { @@ -651,9 +649,16 @@ remote-endpoint = <&funnel_apss_merg_out_funnel_in2>; }; - }; port@2 { + reg = <3>; + funnel_in2_in_funnel_gfx: endpoint { + slave-mode; + remote-endpoint = + <&funnel_gfx_out_funnel_in2>; + }; + }; + port@3 { reg = <4>; funnel_in2_in_tpda_modem: endpoint { slave-mode; @@ -664,6 +669,48 @@ }; }; + funnel_gfx: funnel@0x6943000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6943000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-gfx"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_gfx_out_funnel_in2: endpoint { + remote-endpoint = + <&funnel_in2_in_funnel_gfx>; + }; + }; + port@1 { + reg = <1>; + funnel_gfx_in_gfx: endpoint { + slave-mode; + remote-endpoint = + <&gfx_out_funnel_gfx>; + }; + }; + port@2 { + reg = <2>; + funnel_gfx_in_gfx_cx: endpoint { + slave-mode; + remote-endpoint = + <&gfx_cx_out_funnel_gfx>; + }; + }; + }; + }; + tpda: tpda@6004000 { compatible = "arm,primecell"; arm,primecell-periphid = <0x0003b969>; diff --git a/arch/arm64/boot/dts/qcom/sm8150-gpu.dtsi b/arch/arm64/boot/dts/qcom/sm8150-gpu.dtsi index 564f055bc730..3dbcdb82af51 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-gpu.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-gpu.dtsi @@ -91,13 +91,15 @@ qcom,ubwc-mode = <3>; - qcom,snapshot-size = <1310720>; //bytes + qcom,snapshot-size = <0x200000>; //bytes qcom,gpu-qdss-stm = <0x161c0000 0x40000>; // base addr, size qcom,tsens-name = "tsens_tz_sensor12"; #cooling-cells = <2>; + tzone-names = "gpuss-0-usr", "gpuss-1-usr"; + qcom,pm-qos-active-latency = <44>; clocks = <&clock_gpucc GPU_CC_CXO_CLK>, @@ -149,6 +151,36 @@ cache-slice-names = "gpu", "gpuhtw"; cache-slices = <&llcc 12>, <&llcc 11>; + + qcom,gpu-coresights { + #address-cells = <1>; + #size-cells = <0>; + compatible = "qcom,gpu-coresight"; + + qcom,gpu-coresight@0 { + reg = <0>; + coresight-name = "coresight-gfx"; + coresight-atid = <50>; + port { + gfx_out_funnel_gfx: endpoint { + remote-endpoint = + <&funnel_gfx_in_gfx>; + }; + }; + }; + qcom,gpu-coresight@1 { + reg = <1>; + coresight-name = "coresight-gfx-cx"; + coresight-atid = <51>; + port { + gfx_cx_out_funnel_gfx: endpoint { + remote-endpoint = + <&funnel_gfx_in_gfx_cx>; + }; + }; + }; + }; + qcom,l3-pwrlevels { #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm64/boot/dts/qcom/sm8150-mhi.dtsi b/arch/arm64/boot/dts/qcom/sm8150-mhi.dtsi index 3a6f369fef0c..07ca8d22b752 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-mhi.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-mhi.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2019, 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 @@ -425,6 +425,11 @@ mhi,interface-name = "rmnet_mhi"; mhi,mru = <0x4000>; }; + + mhi_qrtr { + mhi,chan = "IPCR"; + mhi,early-notify; + }; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi index eff9ec22d83b..4d3fdfb0c5a2 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2019, 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 @@ -394,7 +394,6 @@ qcom,mdss-default-ot-wr-limit = <32>; qcom,mdss-sbuf-headroom = <20>; - qcom,mdss-rot-linewidth = <8192>; cache-slice-names = "rotator"; cache-slices = <&llcc 4>; diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c index 0195d76666f4..1bbfc8186eee 100644 --- a/arch/arm64/mm/dma-mapping.c +++ b/arch/arm64/mm/dma-mapping.c @@ -843,6 +843,7 @@ static int __iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma, { struct vm_struct *area; int ret; + unsigned long pfn = 0; vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot, is_dma_coherent(dev, attrs)); @@ -850,20 +851,23 @@ static int __iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma, if (dma_mmap_from_dev_coherent(dev, vma, cpu_addr, size, &ret)) return ret; - if (attrs & DMA_ATTR_FORCE_CONTIGUOUS) { + area = find_vm_area(cpu_addr); + + if (area && area->pages) + return iommu_dma_mmap(area->pages, size, vma); + else if (!is_vmalloc_addr(cpu_addr)) + pfn = page_to_pfn(virt_to_page(cpu_addr)); + else if (is_vmalloc_addr(cpu_addr)) /* - * DMA_ATTR_FORCE_CONTIGUOUS allocations are always remapped, - * hence in the vmalloc space. + * DMA_ATTR_FORCE_CONTIGUOUS and atomic pool allocations are + * always remapped, hence in the vmalloc space. */ - unsigned long pfn = vmalloc_to_pfn(cpu_addr); - return __swiotlb_mmap_pfn(vma, pfn, size); - } + pfn = vmalloc_to_pfn(cpu_addr); - area = find_vm_area(cpu_addr); - if (WARN_ON(!area || !area->pages)) - return -ENXIO; + if (pfn) + return __swiotlb_mmap_pfn(vma, pfn, size); - return iommu_dma_mmap(area->pages, size, vma); + return -ENXIO; } static int __iommu_get_sgtable(struct device *dev, struct sg_table *sgt, @@ -871,22 +875,24 @@ static int __iommu_get_sgtable(struct device *dev, struct sg_table *sgt, size_t size, unsigned long attrs) { unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT; + struct page *page = NULL; struct vm_struct *area = find_vm_area(cpu_addr); - if (attrs & DMA_ATTR_FORCE_CONTIGUOUS) { + if (area && area->pages) + return sg_alloc_table_from_pages(sgt, area->pages, count, 0, + size, GFP_KERNEL); + else if (!is_vmalloc_addr(cpu_addr)) + page = virt_to_page(cpu_addr); + else if (is_vmalloc_addr(cpu_addr)) /* - * DMA_ATTR_FORCE_CONTIGUOUS allocations are always remapped, - * hence in the vmalloc space. + * DMA_ATTR_FORCE_CONTIGUOUS and atomic pool allocations + * are always remapped, hence in the vmalloc space. */ - struct page *page = vmalloc_to_page(cpu_addr); - return __swiotlb_get_sgtable_page(sgt, page, size); - } + page = vmalloc_to_page(cpu_addr); - if (WARN_ON(!area || !area->pages)) - return -ENXIO; - - return sg_alloc_table_from_pages(sgt, area->pages, count, 0, size, - GFP_KERNEL); + if (page) + return __swiotlb_get_sgtable_page(sgt, page, size); + return -ENXIO; } static void __iommu_sync_single_for_cpu(struct device *dev, diff --git a/drivers/bus/mhi/controllers/mhi_arch_qcom.c b/drivers/bus/mhi/controllers/mhi_arch_qcom.c index 46932182ad8b..186d42d22e28 100644 --- a/drivers/bus/mhi/controllers/mhi_arch_qcom.c +++ b/drivers/bus/mhi/controllers/mhi_arch_qcom.c @@ -189,6 +189,18 @@ static void mhi_arch_esoc_ops_power_off(void *priv, unsigned int flags) pm_relax(&mhi_cntrl->mhi_dev->dev); } +static void mhi_arch_esoc_ops_mdm_error(void *priv) +{ + struct mhi_controller *mhi_cntrl = priv; + + MHI_LOG("Enter: mdm asserted\n"); + + /* transition MHI state into error state */ + mhi_control_error(mhi_cntrl); + + MHI_LOG("Exit\n"); +} + static void mhi_bl_dl_cb(struct mhi_device *mhi_dev, struct mhi_result *mhi_result) { @@ -362,6 +374,8 @@ int mhi_arch_pcie_init(struct mhi_controller *mhi_cntrl) mhi_arch_esoc_ops_power_on; esoc_ops->esoc_link_power_off = mhi_arch_esoc_ops_power_off; + esoc_ops->esoc_link_mdm_crash = + mhi_arch_esoc_ops_mdm_error; ret = esoc_register_client_hook(arch_info->esoc_client, esoc_ops); diff --git a/drivers/bus/mhi/core/mhi_init.c b/drivers/bus/mhi/core/mhi_init.c index ed473292afde..9a38d43a52c4 100644 --- a/drivers/bus/mhi/core/mhi_init.c +++ b/drivers/bus/mhi/core/mhi_init.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2019, 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 @@ -1344,7 +1344,7 @@ static int mhi_driver_probe(struct device *dev) int ret; /* bring device out of lpm */ - ret = mhi_device_get_sync(mhi_dev); + ret = mhi_device_get_sync(mhi_dev, 0); if (ret) return ret; @@ -1392,7 +1392,7 @@ static int mhi_driver_probe(struct device *dev) mhi_prepare_for_transfer(mhi_dev); exit_probe: - mhi_device_put(mhi_dev); + mhi_device_put(mhi_dev, 0); return ret; } @@ -1470,7 +1470,7 @@ static int mhi_driver_remove(struct device *dev) /* relinquish any pending votes */ read_lock_bh(&mhi_cntrl->pm_lock); while (atomic_read(&mhi_dev->dev_wake)) - mhi_device_put(mhi_dev); + mhi_device_put(mhi_dev, 0); read_unlock_bh(&mhi_cntrl->pm_lock); return 0; diff --git a/drivers/bus/mhi/core/mhi_internal.h b/drivers/bus/mhi/core/mhi_internal.h index a00181abaad5..1f0c0ebb0b33 100644 --- a/drivers/bus/mhi/core/mhi_internal.h +++ b/drivers/bus/mhi/core/mhi_internal.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2019, 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 @@ -724,6 +724,7 @@ int mhi_get_capability_offset(struct mhi_controller *mhi_cntrl, u32 capability, int mhi_init_timesync(struct mhi_controller *mhi_cntrl); int mhi_create_timesync_sysfs(struct mhi_controller *mhi_cntrl); void mhi_destroy_timesync(struct mhi_controller *mhi_cntrl); +int mhi_early_notify_device(struct device *dev, void *data); /* memory allocation methods */ static inline void *mhi_alloc_coherent(struct mhi_controller *mhi_cntrl, diff --git a/drivers/bus/mhi/core/mhi_main.c b/drivers/bus/mhi/core/mhi_main.c index 7e492277039c..3dd7af61c3f1 100644 --- a/drivers/bus/mhi/core/mhi_main.c +++ b/drivers/bus/mhi/core/mhi_main.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2019, 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 @@ -572,6 +572,22 @@ int mhi_destroy_device(struct device *dev, void *data) return 0; } +int mhi_early_notify_device(struct device *dev, void *data) +{ + struct mhi_device *mhi_dev = to_mhi_device(dev); + struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; + + /* skip early notification */ + if (!mhi_dev->early_notif) + return 0; + + MHI_LOG("Early notification for dev:%s\n", mhi_dev->chan_name); + + mhi_notify(mhi_dev, MHI_CB_FATAL_ERROR); + + return 0; +} + void mhi_notify(struct mhi_device *mhi_dev, enum MHI_CB cb_reason) { struct mhi_driver *mhi_drv; @@ -780,6 +796,13 @@ void mhi_create_devices(struct mhi_controller *mhi_cntrl) /* add if there is a matching DT node */ mhi_assign_of_node(mhi_cntrl, mhi_dev); + /* + * if set, these device should get a early notification during + * early notification state + */ + mhi_dev->early_notif = + of_property_read_bool(mhi_dev->dev.of_node, + "mhi,early-notify"); /* init wake source */ if (mhi_dev->dl_chan && mhi_dev->dl_chan->wake_capable) device_init_wakeup(&mhi_dev->dev, true); diff --git a/drivers/bus/mhi/core/mhi_pm.c b/drivers/bus/mhi/core/mhi_pm.c index 30fa55f44f9b..190d0ffad300 100644 --- a/drivers/bus/mhi/core/mhi_pm.c +++ b/drivers/bus/mhi/core/mhi_pm.c @@ -853,6 +853,36 @@ error_dev_ctxt: } EXPORT_SYMBOL(mhi_async_power_up); +/* Transition MHI into error state and notify critical clients */ +void mhi_control_error(struct mhi_controller *mhi_cntrl) +{ + enum MHI_PM_STATE cur_state; + + MHI_LOG("Enter with pm_state:%s MHI_STATE:%s\n", + to_mhi_pm_state_str(mhi_cntrl->pm_state), + TO_MHI_STATE_STR(mhi_cntrl->dev_state)); + + write_lock_irq(&mhi_cntrl->pm_lock); + cur_state = mhi_tryset_pm_state(mhi_cntrl, MHI_PM_LD_ERR_FATAL_DETECT); + write_unlock_irq(&mhi_cntrl->pm_lock); + + if (cur_state != MHI_PM_LD_ERR_FATAL_DETECT) { + MHI_ERR("Failed to transition to state:%s from:%s\n", + to_mhi_pm_state_str(MHI_PM_LD_ERR_FATAL_DETECT), + to_mhi_pm_state_str(cur_state)); + goto exit_control_error; + } + + /* start notifying all clients who request early notification */ + device_for_each_child(mhi_cntrl->dev, NULL, mhi_early_notify_device); + +exit_control_error: + MHI_LOG("Exit with pm_state:%s MHI_STATE:%s\n", + to_mhi_pm_state_str(mhi_cntrl->pm_state), + TO_MHI_STATE_STR(mhi_cntrl->dev_state)); +} +EXPORT_SYMBOL(mhi_control_error); + void mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful) { enum MHI_PM_STATE cur_state; @@ -1091,7 +1121,7 @@ int __mhi_device_get_sync(struct mhi_controller *mhi_cntrl) return 0; } -void mhi_device_get(struct mhi_device *mhi_dev) +void mhi_device_get(struct mhi_device *mhi_dev, int vote) { struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; @@ -1102,7 +1132,7 @@ void mhi_device_get(struct mhi_device *mhi_dev) } EXPORT_SYMBOL(mhi_device_get); -int mhi_device_get_sync(struct mhi_device *mhi_dev) +int mhi_device_get_sync(struct mhi_device *mhi_dev, int vote) { struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; int ret; @@ -1115,7 +1145,7 @@ int mhi_device_get_sync(struct mhi_device *mhi_dev) } EXPORT_SYMBOL(mhi_device_get_sync); -void mhi_device_put(struct mhi_device *mhi_dev) +void mhi_device_put(struct mhi_device *mhi_dev, int vote) { struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; diff --git a/drivers/bus/mhi/devices/mhi_netdev.c b/drivers/bus/mhi/devices/mhi_netdev.c index 11b757ed0f47..016bf6b6134c 100644 --- a/drivers/bus/mhi/devices/mhi_netdev.c +++ b/drivers/bus/mhi/devices/mhi_netdev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2019, 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 @@ -371,12 +371,12 @@ static int mhi_netdev_ioctl_extended(struct net_device *dev, struct ifreq *ifr) /* Request to enable LPM */ MSG_VERB("Enable MHI LPM"); mhi_netdev->wake--; - mhi_device_put(mhi_dev); + mhi_device_put(mhi_dev, 0); } else if (!ext_cmd.u.data && !mhi_netdev->wake) { /* Request to disable LPM */ MSG_VERB("Disable MHI LPM"); mhi_netdev->wake++; - mhi_device_get(mhi_dev); + mhi_device_get(mhi_dev, 0); } } else { MSG_ERR("Cannot set LPM value, MHI is not up.\n"); diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c index b6cc522864c1..9762d23b42cc 100644 --- a/drivers/char/diag/diag_masks.c +++ b/drivers/char/diag/diag_masks.c @@ -1206,7 +1206,7 @@ static int diag_cmd_get_log_mask(unsigned char *src_buf, int src_len, int rsp_header_len = sizeof(struct diag_log_config_rsp_t); uint32_t mask_size = 0; struct diag_log_mask_t *log_item = NULL; - struct diag_log_config_req_t *req; + struct diag_log_config_get_req_t *req; struct diag_log_config_rsp_t rsp; struct diag_mask_info *mask_info = NULL; struct diag_md_session_t *info = NULL; @@ -1216,7 +1216,7 @@ static int diag_cmd_get_log_mask(unsigned char *src_buf, int src_len, mask_info = (!info) ? &log_mask : info->log_mask; if (!src_buf || !dest_buf || dest_len <= 0 || !mask_info || - src_len < sizeof(struct diag_log_config_req_t)) { + src_len < sizeof(struct diag_log_config_get_req_t)) { pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n", __func__, src_buf, src_len, dest_buf, dest_len, mask_info); @@ -1235,7 +1235,7 @@ static int diag_cmd_get_log_mask(unsigned char *src_buf, int src_len, return 0; } - req = (struct diag_log_config_req_t *)src_buf; + req = (struct diag_log_config_get_req_t *)src_buf; read_len += req_header_len; rsp.cmd_code = DIAG_CMD_LOG_CONFIG; diff --git a/drivers/char/diag/diag_masks.h b/drivers/char/diag/diag_masks.h index 0ccadf30f092..53966e58284c 100644 --- a/drivers/char/diag/diag_masks.h +++ b/drivers/char/diag/diag_masks.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, 2017-2018 The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2015, 2017-2019 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 @@ -40,6 +40,13 @@ struct diag_msg_mask_t { uint32_t *ptr; }; +struct diag_log_config_get_req_t { + uint8_t cmd_code; + uint8_t padding[3]; + uint32_t sub_cmd; + uint32_t equip_id; +} __packed; + struct diag_log_config_req_t { uint8_t cmd_code; uint8_t padding[3]; diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c b/drivers/gpu/drm/msm/dp/dp_aux.c index 9c38205b1b02..2067285f6b71 100644 --- a/drivers/gpu/drm/msm/dp/dp_aux.c +++ b/drivers/gpu/drm/msm/dp/dp_aux.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2019, 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 @@ -320,7 +320,7 @@ static void dp_aux_reconfig(struct dp_aux *dp_aux) aux->catalog->reset(aux->catalog); } -static void dp_aux_abort_transaction(struct dp_aux *dp_aux) +static void dp_aux_abort_transaction(struct dp_aux *dp_aux, bool reset) { struct dp_aux_private *aux; @@ -331,7 +331,7 @@ static void dp_aux_abort_transaction(struct dp_aux *dp_aux) aux = container_of(dp_aux, struct dp_aux_private, dp_aux); - atomic_set(&aux->aborted, 1); + atomic_set(&aux->aborted, !reset); } static void dp_aux_update_offset_and_segment(struct dp_aux_private *aux, diff --git a/drivers/gpu/drm/msm/dp/dp_aux.h b/drivers/gpu/drm/msm/dp/dp_aux.h index c0d0bf343fcd..d683241e36cf 100644 --- a/drivers/gpu/drm/msm/dp/dp_aux.h +++ b/drivers/gpu/drm/msm/dp/dp_aux.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2019, 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 @@ -55,7 +55,7 @@ struct dp_aux { void (*init)(struct dp_aux *aux, struct dp_aux_cfg *aux_cfg); void (*deinit)(struct dp_aux *aux); void (*reconfig)(struct dp_aux *aux); - void (*abort)(struct dp_aux *aux); + void (*abort)(struct dp_aux *aux, bool reset); void (*dpcd_updated)(struct dp_aux *aux); void (*set_sim_mode)(struct dp_aux *aux, bool en, u8 *edid, u8 *dpcd); int (*aux_switch)(struct dp_aux *aux, bool enable, int orientation); diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c index f7f8b1ab71ff..1108e45d1471 100644 --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c @@ -105,7 +105,7 @@ static void dp_ctrl_video_ready(struct dp_ctrl_private *ctrl) complete(&ctrl->video_comp); } -static void dp_ctrl_abort(struct dp_ctrl *dp_ctrl) +static void dp_ctrl_abort(struct dp_ctrl *dp_ctrl, bool reset) { struct dp_ctrl_private *ctrl; @@ -116,7 +116,7 @@ static void dp_ctrl_abort(struct dp_ctrl *dp_ctrl) ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); - atomic_set(&ctrl->aborted, 1); + atomic_set(&ctrl->aborted, !reset); } static void dp_ctrl_state_ctrl(struct dp_ctrl_private *ctrl, u32 state) @@ -408,7 +408,7 @@ static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl) } ctrl->catalog->set_pattern(ctrl->catalog, pattern); ret = dp_ctrl_train_pattern_set(ctrl, - pattern | DP_RECOVERED_CLOCK_OUT_EN); + pattern | DP_LINK_SCRAMBLING_DISABLE); if (ret <= 0) { ret = -EINVAL; goto end; diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.h b/drivers/gpu/drm/msm/dp/dp_ctrl.h index d26e9cc63d97..9ea379b32a21 100644 --- a/drivers/gpu/drm/msm/dp/dp_ctrl.h +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2019, 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 @@ -28,7 +28,7 @@ struct dp_ctrl { int (*on)(struct dp_ctrl *dp_ctrl, bool mst_mode, bool fec_en, bool shallow); void (*off)(struct dp_ctrl *dp_ctrl); - void (*abort)(struct dp_ctrl *dp_ctrl); + void (*abort)(struct dp_ctrl *dp_ctrl, bool reset); void (*isr)(struct dp_ctrl *dp_ctrl); bool (*handle_sink_request)(struct dp_ctrl *dp_ctrl); void (*process_phy_test_request)(struct dp_ctrl *dp_ctrl); diff --git a/drivers/gpu/drm/msm/dp/dp_debug.c b/drivers/gpu/drm/msm/dp/dp_debug.c index f057f96b6ce5..7eab05c7849d 100644 --- a/drivers/gpu/drm/msm/dp/dp_debug.c +++ b/drivers/gpu/drm/msm/dp/dp_debug.c @@ -1464,8 +1464,8 @@ static void dp_debug_set_sim_mode(struct dp_debug_private *debug, bool sim) debug->aux->set_sim_mode(debug->aux, true, debug->edid, debug->dpcd); } else { - debug->aux->abort(debug->aux); - debug->ctrl->abort(debug->ctrl); + debug->aux->abort(debug->aux, false); + debug->ctrl->abort(debug->ctrl, false); debug->aux->set_sim_mode(debug->aux, false, NULL, NULL); debug->power->sim_mode = false; diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index 929543f9527c..1e85c3c47c8e 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -639,6 +639,11 @@ static int dp_display_send_hpd_notification(struct dp_display_private *dp) reinit_completion(&dp->notification_comp); dp_display_send_hpd_event(dp); + if (dp->suspended) { + pr_debug("DP in suspend state. Skip wait for notification\n"); + goto skip_wait; + } + if (hpd && dp->mst.mst_active) goto skip_wait; @@ -650,9 +655,8 @@ static int dp_display_send_hpd_notification(struct dp_display_private *dp) pr_warn("%s timeout\n", hpd ? "connect" : "disconnect"); ret = -EINVAL; } - return ret; skip_wait: - return 0; + return ret; } static void dp_display_update_mst_state(struct dp_display_private *dp, @@ -784,6 +788,8 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp) dp->dp_display.max_pclk_khz = min(dp->parser->max_pclk_khz, dp->debug->max_pclk_khz); + dp->dp_display.max_hdisplay = dp->parser->max_hdisplay; + dp->dp_display.max_vdisplay = dp->parser->max_vdisplay; dp_display_host_init(dp); @@ -985,8 +991,8 @@ static int dp_display_handle_disconnect(struct dp_display_private *dp) rc = dp_display_process_hpd_low(dp); if (rc) { /* cancel any pending request */ - dp->ctrl->abort(dp->ctrl); - dp->aux->abort(dp->aux); + dp->ctrl->abort(dp->ctrl, false); + dp->aux->abort(dp->aux, false); } mutex_lock(&dp->session_lock); @@ -1004,8 +1010,8 @@ static void dp_display_disconnect_sync(struct dp_display_private *dp) { /* cancel any pending request */ atomic_set(&dp->aborted, 1); - dp->ctrl->abort(dp->ctrl); - dp->aux->abort(dp->aux); + dp->ctrl->abort(dp->ctrl, false); + dp->aux->abort(dp->aux, false); /* wait for idle state */ cancel_work(&dp->connect_work); @@ -1974,6 +1980,16 @@ static enum drm_mode_status dp_display_validate_mode( goto end; } + if (dp_display->max_hdisplay > 0 && dp_display->max_vdisplay > 0 && + ((mode->hdisplay > dp_display->max_hdisplay) || + (mode->vdisplay > dp_display->max_vdisplay))) { + DP_MST_DEBUG("hdisplay:%d, max-hdisplay:%d", + mode->hdisplay, dp_display->max_hdisplay); + DP_MST_DEBUG(" vdisplay:%d, max-vdisplay:%d\n", + mode->vdisplay, dp_display->max_vdisplay); + goto end; + } + /* * If the connector exists in the mst connector list and if debug is * enabled for that connector, use the mst connector settings from the @@ -2649,9 +2665,22 @@ static int dp_pm_prepare(struct device *dev) struct dp_display_private *dp = container_of(g_dp_display, struct dp_display_private, dp_display); + dp->suspended = true; + dp_display_set_mst_state(g_dp_display, PM_SUSPEND); - dp->suspended = true; + /* + * There are a few instances where the DP is hotplugged when the device + * is in PM suspend state. After hotplug, it is observed the device + * enters and exits the PM suspend multiple times while aux transactions + * are taking place. This may sometimes cause an unclocked register + * access error. So, abort aux transactions when such a situation + * arises i.e. when DP is connected but not powered on yet. + */ + if (dp->is_connected && !dp->power_on) { + dp->aux->abort(dp->aux, false); + dp->ctrl->abort(dp->ctrl, false); + } return 0; } @@ -2664,6 +2693,19 @@ static void dp_pm_complete(struct device *dev) dp_display_set_mst_state(g_dp_display, PM_DEFAULT); dp->suspended = false; + + /* + * There are multiple PM suspend entry and exits observed before + * the connect uevent is issued to userspace. The aux transactions are + * aborted during PM suspend entry in dp_pm_prepare to prevent unclocked + * register access. On PM suspend exit, there will be no host_init call + * to reset the abort flags for ctrl and aux incase the DP is connected + * but not powered on. So, resetting the abort flags for aux and ctrl. + */ + if (dp->is_connected && !dp->power_on) { + dp->aux->abort(dp->aux, true); + dp->ctrl->abort(dp->ctrl, true); + } } static const struct dev_pm_ops dp_pm_ops = { diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h index 2eb1e80f706e..e18fc52ed406 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.h +++ b/drivers/gpu/drm/msm/dp/dp_display.h @@ -76,6 +76,8 @@ struct dp_display { bool is_sst_connected; bool is_mst_supported; u32 max_pclk_khz; + u32 max_hdisplay; + u32 max_vdisplay; void *dp_mst_prv_info; int (*enable)(struct dp_display *dp_display, void *panel); diff --git a/drivers/gpu/drm/msm/dp/dp_parser.c b/drivers/gpu/drm/msm/dp/dp_parser.c index 2aa922b77868..199f114c8c11 100644 --- a/drivers/gpu/drm/msm/dp/dp_parser.c +++ b/drivers/gpu/drm/msm/dp/dp_parser.c @@ -176,6 +176,12 @@ static int dp_parser_misc(struct dp_parser *parser) if (rc) parser->max_lclk_khz = DP_MAX_LINK_CLK_KHZ; + rc = of_property_read_u32(of_node, + "qcom,max-hdisplay", &parser->max_hdisplay); + + rc = of_property_read_u32(of_node, + "qcom,max-vdisplay", &parser->max_vdisplay); + return 0; } diff --git a/drivers/gpu/drm/msm/dp/dp_parser.h b/drivers/gpu/drm/msm/dp/dp_parser.h index bafc2b977574..81db5d38a4c7 100644 --- a/drivers/gpu/drm/msm/dp/dp_parser.h +++ b/drivers/gpu/drm/msm/dp/dp_parser.h @@ -194,6 +194,8 @@ static inline char *dp_phy_aux_config_type_to_string(u32 cfg_type) * @l_pnswap: P/N swap status on each lane * @max_pclk_khz: maximum pixel clock supported for the platform * @max_lclk_khz: maximum link clock supported for the platform + * @max_hdisplay: maximum supported horizontal display by the platform for dp + * @max_vdisplay: maximum supported vertical display by the platform for dp * @hw_cfg: DP HW specific settings * @has_mst: MST feature enable status * @has_mst_sideband: MST sideband feature enable status @@ -222,6 +224,8 @@ struct dp_parser { struct dp_aux_cfg aux_cfg[AUX_CFG_LEN]; u32 max_pclk_khz; u32 max_lclk_khz; + u32 max_hdisplay; + u32 max_vdisplay; struct dp_hw_cfg hw_cfg; bool has_mst; bool has_mst_sideband; diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index eb7551ef3f13..200a942152e1 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -2096,6 +2096,14 @@ static int _adreno_start(struct adreno_device *adreno_dev) if (status) goto error_oob_clear; + /* + * At this point it is safe to assume that we recovered. Setting + * this field allows us to take a new snapshot for the next failure + * if we are prioritizing the first unrecoverable snapshot. + */ + if (device->snapshot) + device->snapshot->recovered = true; + /* Start the dispatcher */ adreno_dispatcher_start(device); diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c index bba99f9f0f15..1f7d86bdf37a 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -35,9 +35,17 @@ static const unsigned int a6xx_gmu_gx_registers[] = { 0x1A900, 0x1A92B, 0x1A940, 0x1A940, }; +static const unsigned int a6xx_gmu_itcm_registers[] = { + /* GMU ITCM */ + 0x1B400, 0x1C3FF, +}; + +static const unsigned int a6xx_gmu_dtcm_registers[] = { + /* GMU DTCM */ + 0x1C400, 0x1D3FF, +}; + static const unsigned int a6xx_gmu_registers[] = { - /* GMU TCM */ - 0x1B400, 0x1C3FF, 0x1C400, 0x1D3FF, /* GMU CX */ 0x1F400, 0x1F407, 0x1F410, 0x1F412, 0x1F500, 0x1F500, 0x1F507, 0x1F50A, 0x1F800, 0x1F804, 0x1F807, 0x1F808, 0x1F80B, 0x1F80C, 0x1F80F, 0x1F81C, @@ -1431,6 +1439,40 @@ static unsigned int a6xx_gmu_ifpc_show(struct adreno_device *adreno_dev) return gmu_core_isenabled(device) && gmu->idle_level >= GPU_HW_IFPC; } +static size_t a6xx_snapshot_gmu_tcm(struct kgsl_device *device, + u8 *buf, size_t remain, void *priv) +{ + struct kgsl_snapshot_gmu_mem *mem_hdr = + (struct kgsl_snapshot_gmu_mem *)buf; + unsigned int *data = (unsigned int *)(buf + sizeof(*mem_hdr)); + unsigned int i, bytes; + unsigned int *type = priv; + const unsigned int *regs; + + if (*type == GMU_ITCM) + regs = a6xx_gmu_itcm_registers; + else + regs = a6xx_gmu_dtcm_registers; + + bytes = (regs[1] - regs[0] + 1) << 2; + + if (remain < bytes + sizeof(*mem_hdr)) { + SNAPSHOT_ERR_NOMEM(device, "GMU Memory"); + return 0; + } + + mem_hdr->type = SNAPSHOT_GMU_MEM_BIN_BLOCK; + mem_hdr->hostaddr = 0; + mem_hdr->gmuaddr = gmu_get_memtype_base(KGSL_GMU_DEVICE(device), *type); + mem_hdr->gpuaddr = 0; + + for (i = regs[0]; i <= regs[1]; i++) + kgsl_regread(device, i, data++); + + return bytes + sizeof(*mem_hdr); +} + + struct gmu_mem_type_desc { struct gmu_memdesc *memdesc; uint32_t type; @@ -1439,27 +1481,31 @@ struct gmu_mem_type_desc { static size_t a6xx_snapshot_gmu_mem(struct kgsl_device *device, u8 *buf, size_t remain, void *priv) { - struct kgsl_snapshot_gmu *header = (struct kgsl_snapshot_gmu *)buf; + struct kgsl_snapshot_gmu_mem *mem_hdr = + (struct kgsl_snapshot_gmu_mem *)buf; struct gmu_mem_type_desc *desc = priv; - unsigned int *data = (unsigned int *)(buf + sizeof(*header)); + unsigned int *data = (unsigned int *)(buf + sizeof(*mem_hdr)); if (priv == NULL) return 0; - if (remain < desc->memdesc->size + sizeof(*header)) { + if (remain < desc->memdesc->size + sizeof(*mem_hdr)) { KGSL_CORE_ERR( "snapshot: Not enough memory for the gmu section %d\n", desc->type); return 0; } - header->type = desc->type; - header->size = desc->memdesc->size; + memset(mem_hdr, 0, sizeof(*mem_hdr)); + mem_hdr->type = desc->type; + mem_hdr->hostaddr = (uintptr_t)desc->memdesc->hostptr; + mem_hdr->gmuaddr = desc->memdesc->gmuaddr; + mem_hdr->gpuaddr = 0; /* Just copy the ringbuffer, there are no active IBs */ memcpy(data, desc->memdesc->hostptr, desc->memdesc->size); - return desc->memdesc->size + sizeof(*header); + return desc->memdesc->size + sizeof(*mem_hdr); } /* @@ -1477,10 +1523,14 @@ static void a6xx_gmu_snapshot(struct adreno_device *adreno_dev, struct gmu_device *gmu = KGSL_GMU_DEVICE(device); bool gx_on; struct gmu_mem_type_desc desc[] = { - {gmu->hfi_mem, SNAPSHOT_GMU_HFIMEM}, - {gmu->gmu_log, SNAPSHOT_GMU_LOG}, - {gmu->dump_mem, SNAPSHOT_GMU_DUMPMEM} }; + {gmu->hfi_mem, SNAPSHOT_GMU_MEM_HFI}, + {gmu->persist_mem, SNAPSHOT_GMU_MEM_BIN_BLOCK}, + {gmu->icache_mem, SNAPSHOT_GMU_MEM_BIN_BLOCK}, + {gmu->dcache_mem, SNAPSHOT_GMU_MEM_BIN_BLOCK}, + {gmu->gmu_log, SNAPSHOT_GMU_MEM_LOG}, + {gmu->dump_mem, SNAPSHOT_GMU_MEM_BIN_BLOCK} }; unsigned int val, i; + enum gmu_mem_type type; if (!gmu_core_isenabled(device)) return; @@ -1488,13 +1538,20 @@ static void a6xx_gmu_snapshot(struct adreno_device *adreno_dev, for (i = 0; i < ARRAY_SIZE(desc); i++) { if (desc[i].memdesc) kgsl_snapshot_add_section(device, - KGSL_SNAPSHOT_SECTION_GMU, + KGSL_SNAPSHOT_SECTION_GMU_MEMORY, snapshot, a6xx_snapshot_gmu_mem, &desc[i]); } + type = GMU_ITCM; + kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_GMU_MEMORY, + snapshot, a6xx_snapshot_gmu_tcm, &type); + type = GMU_DTCM; + kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_GMU_MEMORY, + snapshot, a6xx_snapshot_gmu_tcm, &type); + adreno_snapshot_registers(device, snapshot, a6xx_gmu_registers, - ARRAY_SIZE(a6xx_gmu_registers) / 2); + ARRAY_SIZE(a6xx_gmu_registers) / 2); gx_on = a6xx_gmu_gx_is_on(adreno_dev); diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c index a378dd660928..478af4c725f6 100644 --- a/drivers/gpu/msm/adreno_dispatch.c +++ b/drivers/gpu/msm/adreno_dispatch.c @@ -640,6 +640,17 @@ static int sendcmd(struct adreno_device *adreno_dev, secs = time.ktime; nsecs = do_div(secs, 1000000000); + /* + * For the first submission in any given command queue update the + * expected expire time - this won't actually be used / updated until + * the command queue in question goes current, but universally setting + * it here avoids the possibilty of some race conditions with preempt + */ + + if (dispatch_q->inflight == 1) + dispatch_q->expires = jiffies + + msecs_to_jiffies(adreno_drawobj_timeout); + trace_adreno_cmdbatch_submitted(drawobj, (int) dispatcher->inflight, time.ticks, (unsigned long) secs, nsecs / 1000, drawctxt->rb, adreno_get_rptr(drawctxt->rb)); @@ -653,17 +664,6 @@ static int sendcmd(struct adreno_device *adreno_dev, ADRENO_DISPATCH_DRAWQUEUE_SIZE; /* - * For the first submission in any given command queue update the - * expected expire time - this won't actually be used / updated until - * the command queue in question goes current, but universally setting - * it here avoids the possibilty of some race conditions with preempt - */ - - if (dispatch_q->inflight == 1) - dispatch_q->expires = jiffies + - msecs_to_jiffies(adreno_drawobj_timeout); - - /* * If we believe ourselves to be current and preemption isn't a thing, * then set up the timer. If this misses, then preemption is indeed a * thing and the timer will be set up in due time @@ -2252,14 +2252,6 @@ static int dispatcher_do_fault(struct adreno_device *adreno_dev) atomic_add(halt, &adreno_dev->halt); - /* - * At this point it is safe to assume that we recovered. Setting - * this field allows us to take a new snapshot for the next failure - * if we are prioritizing the first unrecoverable snapshot. - */ - if (device->snapshot) - device->snapshot->recovered = true; - return 1; } diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c index 3ed79af8982d..ab53ff396c63 100644 --- a/drivers/gpu/msm/adreno_snapshot.c +++ b/drivers/gpu/msm/adreno_snapshot.c @@ -70,6 +70,19 @@ void kgsl_snapshot_push_object(struct kgsl_process_private *process, for (index = 0; index < objbufptr; index++) { if (objbuf[index].gpuaddr == gpuaddr && objbuf[index].entry->priv == process) { + /* + * Check if newly requested size is within the + * allocated range or not, otherwise continue + * with previous size. + */ + if (!kgsl_gpuaddr_in_memdesc( + &objbuf[index].entry->memdesc, + gpuaddr, dwords << 2)) { + KGSL_CORE_ERR( + "snapshot: IB 0x%016llx size is not within the memdesc range\n", + gpuaddr); + return; + } objbuf[index].size = max_t(uint64_t, objbuf[index].size, diff --git a/drivers/gpu/msm/adreno_trace.h b/drivers/gpu/msm/adreno_trace.h index bf5e798839b0..e5bc156e5045 100644 --- a/drivers/gpu/msm/adreno_trace.h +++ b/drivers/gpu/msm/adreno_trace.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2019, 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 @@ -577,17 +577,17 @@ TRACE_EVENT(adreno_preempt_trigger, unsigned int cntl), TP_ARGS(cur, next, cntl), TP_STRUCT__entry( - __field(struct adreno_ringbuffer *, cur) - __field(struct adreno_ringbuffer *, next) + __field(unsigned int, cur) + __field(unsigned int, next) __field(unsigned int, cntl) ), TP_fast_assign( - __entry->cur = cur; - __entry->next = next; + __entry->cur = cur->id; + __entry->next = next->id; __entry->cntl = cntl; ), TP_printk("trigger from id=%d to id=%d cntl=%x", - __entry->cur->id, __entry->next->id, __entry->cntl + __entry->cur, __entry->next, __entry->cntl ) ); @@ -596,17 +596,17 @@ TRACE_EVENT(adreno_preempt_done, unsigned int level), TP_ARGS(cur, next, level), TP_STRUCT__entry( - __field(struct adreno_ringbuffer *, cur) - __field(struct adreno_ringbuffer *, next) + __field(unsigned int, cur) + __field(unsigned int, next) __field(unsigned int, level) ), TP_fast_assign( - __entry->cur = cur; - __entry->next = next; + __entry->cur = cur->id; + __entry->next = next->id; __entry->level = level; ), TP_printk("done switch to id=%d from id=%d level=%x", - __entry->next->id, __entry->cur->id, __entry->level + __entry->next, __entry->cur, __entry->level ) ); diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c index 7b9f15f79a7d..41cb7d75242f 100644 --- a/drivers/gpu/msm/kgsl_gmu.c +++ b/drivers/gpu/msm/kgsl_gmu.c @@ -86,6 +86,12 @@ static unsigned int num_uncached_entries; static void gmu_snapshot(struct kgsl_device *device); static void gmu_remove(struct kgsl_device *device); +unsigned int gmu_get_memtype_base(struct gmu_device *gmu, + enum gmu_mem_type type) +{ + return gmu_vma[type].start; +} + static int _gmu_iommu_fault_handler(struct device *dev, unsigned long addr, int flags, const char *name) { @@ -363,6 +369,9 @@ static void gmu_kmem_close(struct gmu_device *gmu) struct gmu_iommu_context *ctx = &gmu_ctx[GMU_CONTEXT_KERNEL]; gmu->hfi_mem = NULL; + gmu->persist_mem = NULL; + gmu->icache_mem = NULL; + gmu->dcache_mem = NULL; gmu->dump_mem = NULL; gmu->gmu_log = NULL; @@ -431,32 +440,39 @@ static int gmu_memory_probe(struct kgsl_device *device, /* Allocates & maps memory for WB DUMMY PAGE */ /* Must be the first alloc */ - md = allocate_gmu_kmem(gmu, GMU_NONCACHED_KERNEL, - DUMMY_SIZE, (IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV)); - if (IS_ERR(md)) { - ret = PTR_ERR(md); + if (IS_ERR_OR_NULL(gmu->persist_mem)) + gmu->persist_mem = allocate_gmu_kmem(gmu, GMU_NONCACHED_KERNEL, + DUMMY_SIZE, + (IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV)); + if (IS_ERR(gmu->persist_mem)) { + ret = PTR_ERR(gmu->persist_mem); goto err_ret; } /* Allocates & maps memory for DCACHE */ - md = allocate_gmu_kmem(gmu, GMU_DCACHE, gmu_vma[GMU_DCACHE].size, - (IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV)); - if (IS_ERR(md)) { - ret = PTR_ERR(md); + if (IS_ERR_OR_NULL(gmu->dcache_mem)) + gmu->dcache_mem = allocate_gmu_kmem(gmu, GMU_DCACHE, + gmu_vma[GMU_DCACHE].size, + (IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV)); + if (IS_ERR(gmu->dcache_mem)) { + ret = PTR_ERR(gmu->dcache_mem); goto err_ret; } /* Allocates & maps memory for ICACHE */ - md = allocate_gmu_kmem(gmu, GMU_ICACHE, gmu_vma[GMU_ICACHE].size, - (IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV)); - if (IS_ERR(md)) { - ret = PTR_ERR(md); + if (IS_ERR_OR_NULL(gmu->icache_mem)) + gmu->icache_mem = allocate_gmu_kmem(gmu, GMU_ICACHE, + gmu_vma[GMU_ICACHE].size, + (IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV)); + if (IS_ERR(gmu->icache_mem)) { + ret = PTR_ERR(gmu->icache_mem); goto err_ret; } /* Allocates & maps memory for HFI */ - gmu->hfi_mem = allocate_gmu_kmem(gmu, GMU_NONCACHED_KERNEL, HFIMEM_SIZE, - (IOMMU_READ | IOMMU_WRITE)); + if (IS_ERR_OR_NULL(gmu->hfi_mem)) + gmu->hfi_mem = allocate_gmu_kmem(gmu, GMU_NONCACHED_KERNEL, + HFIMEM_SIZE, (IOMMU_READ | IOMMU_WRITE)); if (IS_ERR(gmu->hfi_mem)) { ret = PTR_ERR(gmu->hfi_mem); goto err_ret; @@ -464,8 +480,11 @@ static int gmu_memory_probe(struct kgsl_device *device, /* Allocates & maps GMU crash dump memory */ if (adreno_is_a630(adreno_dev) || adreno_is_a615_family(adreno_dev)) { - gmu->dump_mem = allocate_gmu_kmem(gmu, GMU_NONCACHED_KERNEL, - DUMPMEM_SIZE, (IOMMU_READ | IOMMU_WRITE)); + if (IS_ERR_OR_NULL(gmu->dump_mem)) + gmu->dump_mem = allocate_gmu_kmem(gmu, + GMU_NONCACHED_KERNEL, + DUMPMEM_SIZE, + (IOMMU_READ | IOMMU_WRITE)); if (IS_ERR(gmu->dump_mem)) { ret = PTR_ERR(gmu->dump_mem); goto err_ret; @@ -473,8 +492,10 @@ static int gmu_memory_probe(struct kgsl_device *device, } /* GMU master log */ - gmu->gmu_log = allocate_gmu_kmem(gmu, GMU_NONCACHED_KERNEL, LOGMEM_SIZE, - (IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV)); + if (IS_ERR_OR_NULL(gmu->gmu_log)) + gmu->gmu_log = allocate_gmu_kmem(gmu, GMU_NONCACHED_KERNEL, + LOGMEM_SIZE, + (IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV)); if (IS_ERR(gmu->gmu_log)) { ret = PTR_ERR(gmu->gmu_log); goto err_ret; diff --git a/drivers/gpu/msm/kgsl_gmu.h b/drivers/gpu/msm/kgsl_gmu.h index cb211ee113eb..24d5f547fb7e 100644 --- a/drivers/gpu/msm/kgsl_gmu.h +++ b/drivers/gpu/msm/kgsl_gmu.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, 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 @@ -132,6 +132,9 @@ struct kgsl_mailbox { * @gmu_interrupt_num: GMU interrupt number * @fw_image: GMU FW image * @hfi_mem: pointer to HFI shared memory + * @icache_mem: pointer to GMU icache memory + * @dcache_mem: pointer to GMU dcache memory + * @persist_mem: pointer to GMU persistent memory * @dump_mem: pointer to GMU debug dump memory * @gmu_log: gmu event log memory * @hfi: HFI controller @@ -167,6 +170,9 @@ struct gmu_device { unsigned int gmu_interrupt_num; const struct firmware *fw_image; struct gmu_memdesc *hfi_mem; + struct gmu_memdesc *icache_mem; + struct gmu_memdesc *dcache_mem; + struct gmu_memdesc *persist_mem; struct gmu_memdesc *dump_mem; struct gmu_memdesc *gmu_log; struct kgsl_hfi hfi; @@ -193,5 +199,7 @@ struct gmu_device { }; struct gmu_memdesc *gmu_get_memdesc(unsigned int addr, unsigned int size); +unsigned int gmu_get_memtype_base(struct gmu_device *gmu, + enum gmu_mem_type type); #endif /* __KGSL_GMU_H */ diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index 66a0589c1b3e..18ad2b69c737 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2019, 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 @@ -1498,28 +1498,24 @@ static ssize_t kgsl_pwrctrl_temp_show(struct device *dev, struct kgsl_device *device = kgsl_device_from_dev(dev); struct kgsl_pwrctrl *pwr; struct thermal_zone_device *thermal_dev; - int ret, temperature = 0; + int i, max_temp = 0; if (device == NULL) - goto done; + return 0; pwr = &device->pwrctrl; - if (!pwr->tzone_name) - goto done; + for (i = 0; i < KGSL_MAX_TZONE_NAMES; i++) { + int temp = 0; - thermal_dev = thermal_zone_get_zone_by_name((char *)pwr->tzone_name); - if (thermal_dev == NULL) - goto done; + thermal_dev = thermal_zone_get_zone_by_name( + pwr->tzone_names[i]); + if (!(thermal_zone_get_temp(thermal_dev, &temp))) + max_temp = max_t(int, temp, max_temp); - ret = thermal_zone_get_temp(thermal_dev, &temperature); - if (ret) - goto done; + } - return snprintf(buf, PAGE_SIZE, "%d\n", - temperature); -done: - return 0; + return scnprintf(buf, PAGE_SIZE, "%d\n", max_temp); } static ssize_t kgsl_pwrctrl_pwrscale_store(struct device *dev, @@ -2458,9 +2454,9 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) kgsl_pwrctrl_vbif_init(); /* temperature sensor name */ - of_property_read_string(pdev->dev.of_node, "qcom,tzone-name", - &pwr->tzone_name); + of_property_read_string_array(pdev->dev.of_node, "tzone-names", + pwr->tzone_names, KGSL_MAX_TZONE_NAMES); /* * Cx ipeak client support, default value of Cx Ipeak GPU freq * is used if defined in GPU list and it is overridden by diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h index 421e8d2dd8a4..886a29a5cd07 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.h +++ b/drivers/gpu/msm/kgsl_pwrctrl.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2019, 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 @@ -31,6 +31,8 @@ #define KGSL_MAX_PWRLEVELS 10 +#define KGSL_MAX_TZONE_NAMES 2 + /* Only two supported levels, min & max */ #define KGSL_CONSTRAINT_PWR_MAXLEVELS 2 @@ -171,7 +173,7 @@ struct kgsl_regulator { * @sysfs_pwr_limit - pointer to the sysfs limits node * isense_clk_indx - index of isense clock, 0 if no isense * isense_clk_on_level - isense clock rate is XO rate below this level. - * tzone_name - pointer to thermal zone name of GPU temperature sensor + * tzone_names - array of thermal zone names of GPU temperature sensors * gpu_cx_ipeak - pointer to CX Ipeak client used by GPU * cx_ipeak_gpu_freq - Value of GPU CX Ipeak frequency */ @@ -231,7 +233,7 @@ struct kgsl_pwrctrl { struct kgsl_pwr_limit *sysfs_pwr_limit; unsigned int gpu_bimc_int_clk_freq; bool gpu_bimc_interface_enabled; - const char *tzone_name; + const char *tzone_names[KGSL_MAX_TZONE_NAMES]; struct cx_ipeak_client *gpu_cx_ipeak; unsigned int cx_ipeak_gpu_freq; }; diff --git a/drivers/gpu/msm/kgsl_rgmu.c b/drivers/gpu/msm/kgsl_rgmu.c index bd4069fc7528..23a07b85f77f 100644 --- a/drivers/gpu/msm/kgsl_rgmu.c +++ b/drivers/gpu/msm/kgsl_rgmu.c @@ -200,20 +200,20 @@ static int rgmu_enable_clks(struct kgsl_device *device) } #define CX_GDSC_TIMEOUT 5000 /* ms */ -static int rgmu_disable_gdsc(struct kgsl_device *device) +static void rgmu_disable_gdsc(struct kgsl_device *device) { struct rgmu_device *rgmu = KGSL_RGMU_DEVICE(device); int ret = 0; unsigned long t; if (IS_ERR_OR_NULL(rgmu->cx_gdsc)) - return 0; + return; ret = regulator_disable(rgmu->cx_gdsc); if (ret) { dev_err(&rgmu->pdev->dev, "Failed to disable CX gdsc:%d\n", ret); - return ret; + return; } /* @@ -225,17 +225,13 @@ static int rgmu_disable_gdsc(struct kgsl_device *device) t = jiffies + msecs_to_jiffies(CX_GDSC_TIMEOUT); do { if (!regulator_is_enabled(rgmu->cx_gdsc)) - return 0; + return; usleep_range(10, 100); } while (!(time_after(jiffies, t))); - if (!regulator_is_enabled(rgmu->cx_gdsc)) - return 0; - - dev_err(&rgmu->pdev->dev, "RGMU CX gdsc off timeout\n"); - - return -ETIMEDOUT; + if (regulator_is_enabled(rgmu->cx_gdsc)) + dev_err(&rgmu->pdev->dev, "RGMU CX gdsc off timeout\n"); } static int rgmu_enable_gdsc(struct rgmu_device *rgmu) @@ -413,7 +409,8 @@ static int rgmu_suspend(struct kgsl_device *device) return -EINVAL; rgmu_disable_clks(device); - return rgmu_disable_gdsc(device); + rgmu_disable_gdsc(device); + return 0; } /* To be called to power on both GPU and RGMU */ diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c index 3f6eac33ff07..a1cb0412c277 100644 --- a/drivers/gpu/msm/kgsl_snapshot.c +++ b/drivers/gpu/msm/kgsl_snapshot.c @@ -657,14 +657,20 @@ void kgsl_device_snapshot(struct kgsl_device *device, /* increment the hang count for good book keeping */ device->snapshot_faultcount++; - /* - * Overwrite a fault snapshot only if GMU is - * enabled and we managed to recover from it. - */ if (device->snapshot != NULL) { - if (!gmu_core_gpmu_isenabled(device) || - !device->prioritize_unrecoverable || - !device->snapshot->recovered) + + /* + * Snapshot over-write policy: + * 1. By default, don't over-write the very first snapshot, + * be it a gmu or gpu fault. + * 2. Never over-write existing snapshot on a gpu fault. + * 3. Never over-write a snapshot that we didn't recover from. + * 4. In order to over-write a new gmu fault snapshot with a + * previously recovered fault, then set the sysfs knob + * prioritize_recoverable to true. + */ + if (!device->prioritize_unrecoverable || + !device->snapshot->recovered || !gmu_fault) return; /* @@ -1131,10 +1137,16 @@ int kgsl_device_snapshot_init(struct kgsl_device *device) device->snapshot = NULL; device->snapshot_faultcount = 0; device->force_panic = 0; - device->prioritize_unrecoverable = true; device->snapshot_crashdumper = 1; device->snapshot_legacy = 0; + /* + * Set this to false so that we only ever keep the first snapshot around + * If we want to over-write with a gmu snapshot, then set it to true + * via sysfs + */ + device->prioritize_unrecoverable = false; + ret = kobject_init_and_add(&device->snapshot_kobj, &ktype_snapshot, &device->dev->kobj, "snapshot"); if (ret) diff --git a/drivers/gpu/msm/kgsl_snapshot.h b/drivers/gpu/msm/kgsl_snapshot.h index c1ef28f7eddb..23f6b474f3fe 100644 --- a/drivers/gpu/msm/kgsl_snapshot.h +++ b/drivers/gpu/msm/kgsl_snapshot.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2019, 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 @@ -60,6 +60,7 @@ struct kgsl_snapshot_section_header { #define KGSL_SNAPSHOT_SECTION_SHADER 0x1201 #define KGSL_SNAPSHOT_SECTION_MVC 0x1501 #define KGSL_SNAPSHOT_SECTION_GMU 0x1601 +#define KGSL_SNAPSHOT_SECTION_GMU_MEMORY 0x1701 #define KGSL_SNAPSHOT_SECTION_END 0xFFFF @@ -184,17 +185,20 @@ struct kgsl_snapshot_ib_v2 { __u64 size; /* Size of the IB */ } __packed; -#define SNAPSHOT_GMU_OTHER 0 -#define SNAPSHOT_GMU_HFIMEM 1 -#define SNAPSHOT_GMU_LOG 2 -#define SNAPSHOT_GMU_BWMEM 3 -#define SNAPSHOT_GMU_DUMPMEM 4 -#define SNAPSHOT_GMU_DCACHE 5 +/* GMU memory ID's */ +#define SNAPSHOT_GMU_MEM_UNKNOWN 0x00 +#define SNAPSHOT_GMU_MEM_HFI 0x01 +#define SNAPSHOT_GMU_MEM_LOG 0x02 +#define SNAPSHOT_GMU_MEM_BWTABLE 0x03 +#define SNAPSHOT_GMU_MEM_DEBUG 0x04 +#define SNAPSHOT_GMU_MEM_BIN_BLOCK 0x05 /* Indirect buffer sub-section header */ -struct kgsl_snapshot_gmu { - int type; /* Type of data to dump */ - int size; /* Size in bytes to dump */ +struct kgsl_snapshot_gmu_mem { + int type; + uint64_t hostaddr; + uint64_t gmuaddr; + uint64_t gpuaddr; } __packed; /* Register sub-section header */ 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 f79af9b0c71f..427632667b80 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 @@ -578,7 +578,7 @@ int32_t cam_context_acquire_dev_to_hw(struct cam_context *ctx, req_hdl_param.media_entity_flag = 0; req_hdl_param.priv = ctx; req_hdl_param.ops = ctx->crm_ctx_intf; - + req_hdl_param.dev_id = ctx->dev_id; ctx->dev_hdl = cam_create_device_hdl(&req_hdl_param); if (ctx->dev_hdl <= 0) { rc = -EFAULT; diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c index a05901afba71..4276b356da73 100644 --- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c +++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c @@ -568,7 +568,7 @@ static int cam_cpas_util_set_camnoc_axi_clk_rate( struct cam_cpas_axi_port *curr_axi_port = NULL; struct cam_cpas_axi_port *temp_axi_port = NULL; uint64_t required_camnoc_bw = 0; - int32_t clk_rate = 0; + int64_t clk_rate = 0; list_for_each_entry_safe(curr_axi_port, temp_axi_port, &cpas_core->axi_ports_list_head, sibling_port) { @@ -596,13 +596,13 @@ static int cam_cpas_util_set_camnoc_axi_clk_rate( clk_rate = required_camnoc_bw / soc_private->camnoc_bus_width; - CAM_DBG(CAM_CPAS, "Setting camnoc axi clk rate : %llu %d", + CAM_DBG(CAM_CPAS, "Setting camnoc axi clk rate : %llu %lld", required_camnoc_bw, clk_rate); rc = cam_soc_util_set_src_clk_rate(soc_info, clk_rate); if (rc) CAM_ERR(CAM_CPAS, - "Failed in setting camnoc axi clk %llu %d %d", + "Failed in setting camnoc axi clk %llu %lld %d", required_camnoc_bw, clk_rate, rc); } diff --git a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c index aa970f83424d..a21803ee5945 100644 --- a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c +++ b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, 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 @@ -406,6 +406,12 @@ static void cam_cpastop_work(struct work_struct *work) return; } + mutex_lock(&cpas_hw->hw_mutex); + if (cpas_hw->hw_state == CAM_HW_STATE_POWER_DOWN) { + CAM_ERR(CAM_CPAS, "CPAS CORE is off"); + mutex_unlock(&cpas_hw->hw_mutex); + return; + } for (i = 0; i < camnoc_info->irq_err_size; i++) { if ((payload->irq_status & camnoc_info->irq_err[i].sbm_port) && (camnoc_info->irq_err[i].enable)) { @@ -451,6 +457,7 @@ static void cam_cpastop_work(struct work_struct *work) ~camnoc_info->irq_err[i].sbm_port; } } + mutex_unlock(&cpas_hw->hw_mutex); atomic_dec(&cpas_core->irq_count); wake_up(&cpas_core->irq_count_wq); CAM_DBG(CAM_CPAS, "irq_count=%d\n", atomic_read(&cpas_core->irq_count)); diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c index 8a84c0ee7e99..083041c21dff 100644 --- a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c +++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, 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 @@ -206,10 +206,6 @@ static const struct of_device_id cam_fd_hw_dt_match[] = { .compatible = "qcom,fd501", .data = &cam_fd_wrapper200_core501_info, }, - { - .compatible = "qcom,fd501", - .data = &cam_fd_wrapper200_core501_info, - }, {} }; MODULE_DEVICE_TABLE(of, cam_fd_hw_dt_match); diff --git a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_sys_defs.h b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_sys_defs.h index 311886ffd6da..d60a25e8b925 100644 --- a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_sys_defs.h +++ b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_sys_defs.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, 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 @@ -215,6 +215,27 @@ #define HFI_DEV_VERSION_MAX 0x5 +/* General errors and HFI Specific errors. */ +enum hfi_errors { + CAMERAICP_SUCCESS, + CAMERAICP_EFAILED, + CAMERAICP_ENOMEMORY, + CAMERAICP_EBADSTATE, + CAMERAICP_EBADPARM, + CAMERAICP_EBADITEM, + CAMERAICP_EINVALIDFORMAT, + CAMERAICP_EUNSUPPORTED, + CAMERAICP_EOUTOFBOUND, + CAMERAICP_ETIMEDOUT, + CAMERAICP_EABORTED, + CAMERAICP_EHWVIOLATION, + CAMERAICP_ECDMERROR, + CAMERAICP_HFI_ERR_COMMAND_SIZE = 1000, + CAMERAICP_HFI_ERR_MESSAGE_SIZE, + CAMERAICP_HFI_QUEUE_EMPTY, + CAMERAICP_HFI_QUEUE_FULL, +}; + /** * start of sys command packet types * These commands are used to get system level information diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c index eec56c74d816..51422dac5725 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c @@ -1601,7 +1601,69 @@ static int cam_icp_mgr_handle_frame_process(uint32_t *msg_ptr, int flag) return 0; } +static const char *cam_icp_error_handle_id_to_type( + uint32_t error_handle) +{ + const char *name = NULL; + switch (error_handle) { + case CAMERAICP_SUCCESS: + name = "SUCCESS"; + break; + case CAMERAICP_EFAILED: + name = "EFAILED"; + break; + case CAMERAICP_ENOMEMORY: + name = "ENOMEMORY"; + break; + case CAMERAICP_EBADSTATE: + name = "EBADSTATE"; + break; + case CAMERAICP_EBADPARM: + name = "EBADPARM"; + break; + case CAMERAICP_EBADITEM: + name = "EBADITEM"; + break; + case CAMERAICP_EINVALIDFORMAT: + name = "EINVALIDFORMAT"; + break; + case CAMERAICP_EUNSUPPORTED: + name = "EUNSUPPORTED"; + break; + case CAMERAICP_EOUTOFBOUND: + name = "EOUTOFBOUND"; + break; + case CAMERAICP_ETIMEDOUT: + name = "ETIMEDOUT"; + break; + case CAMERAICP_EABORTED: + name = "EABORTED"; + break; + case CAMERAICP_EHWVIOLATION: + name = "EHWVIOLATION"; + break; + case CAMERAICP_ECDMERROR: + name = "ECDMERROR"; + break; + case CAMERAICP_HFI_ERR_COMMAND_SIZE: + name = "HFI_ERR_COMMAND_SIZE"; + break; + case CAMERAICP_HFI_ERR_MESSAGE_SIZE: + name = "HFI_ERR_MESSAGE_SIZE"; + break; + case CAMERAICP_HFI_QUEUE_EMPTY: + name = "HFI_QUEUE_EMPTY"; + break; + case CAMERAICP_HFI_QUEUE_FULL: + name = "HFI_QUEUE_FULL"; + break; + default: + name = NULL; + break; + } + return name; +} static int cam_icp_mgr_process_msg_frame_process(uint32_t *msg_ptr) { struct hfi_msg_ipebps_async_ack *ioconfig_ack = NULL; @@ -1614,8 +1676,11 @@ static int cam_icp_mgr_process_msg_frame_process(uint32_t *msg_ptr) ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr; if (ioconfig_ack->err_type != HFI_ERR_SYS_NONE) { - CAM_ERR(CAM_ICP, "failed with error : %u", - ioconfig_ack->err_type); + CAM_ERR(CAM_ICP, + "failed with err_no= [%u] err_type= [%s]", + ioconfig_ack->err_type, + cam_icp_error_handle_id_to_type( + ioconfig_ack->err_type)); cam_icp_mgr_handle_frame_process(msg_ptr, ICP_FRAME_PROCESS_FAILURE); return -EIO; @@ -1655,8 +1720,12 @@ static int cam_icp_mgr_process_msg_config_io(uint32_t *msg_ptr) ipe_config_ack = (struct hfi_msg_ipe_config *)(ioconfig_ack->msg_data); if (ipe_config_ack->rc) { - CAM_ERR(CAM_ICP, "rc = %d err = %u", - ipe_config_ack->rc, ioconfig_ack->err_type); + CAM_ERR(CAM_ICP, "rc = %d failed with\n" + "err_no = [%u] err_type = [%s]", + ipe_config_ack->rc, + ioconfig_ack->err_type, + cam_icp_error_handle_id_to_type( + ioconfig_ack->err_type)); return -EIO; } ctx_data = (struct cam_icp_hw_ctx_data *) @@ -1821,9 +1890,13 @@ static int cam_icp_mgr_process_direct_ack_msg(uint32_t *msg_ptr) (struct cam_icp_hw_ctx_data *)ioconfig_ack->user_data1; if (ctx_data->state != CAM_ICP_CTX_STATE_FREE) complete(&ctx_data->wait_complete); - CAM_DBG(CAM_ICP, - "received IPE/BPS MAP ACK:ctx_state =%d err_status =%u", - ctx_data->state, ioconfig_ack->err_type); + CAM_DBG(CAM_ICP, "received IPE/BPS\n" + "MAP ACK:ctx_state =%d\n" + "failed with err_no = [%u] err_type = [%s]", + ctx_data->state, + ioconfig_ack->err_type, + cam_icp_error_handle_id_to_type( + ioconfig_ack->err_type)); break; case HFI_IPEBPS_CMD_OPCODE_MEM_UNMAP: ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr; @@ -1831,9 +1904,13 @@ static int cam_icp_mgr_process_direct_ack_msg(uint32_t *msg_ptr) (struct cam_icp_hw_ctx_data *)ioconfig_ack->user_data1; if (ctx_data->state != CAM_ICP_CTX_STATE_FREE) complete(&ctx_data->wait_complete); - CAM_DBG(CAM_ICP, - "received IPE/BPS UNMAP ACK:ctx_state =%d err_status =%u", - ctx_data->state, ioconfig_ack->err_type); + CAM_DBG(CAM_ICP, + "received IPE/BPS UNMAP ACK:ctx_state =%d\n" + "failed with err_no = [%u] err_type = [%s]", + ctx_data->state, + ioconfig_ack->err_type, + cam_icp_error_handle_id_to_type( + ioconfig_ack->err_type)); break; default: CAM_ERR(CAM_ICP, "Invalid opcode : %u", @@ -4613,6 +4690,13 @@ static int cam_icp_get_acquire_info(struct cam_icp_hw_mgr *hw_mgr, return -EFAULT; } + /* To make sure num_out_res is same as allocated */ + if (ctx_data->icp_dev_acquire_info->num_out_res != + icp_dev_acquire_info.num_out_res) { + CAM_ERR(CAM_ICP, "num_out_res got changed"); + return -EFAULT; + } + CAM_DBG(CAM_ICP, "%x %x %x %x %x %x %x", ctx_data->icp_dev_acquire_info->dev_type, ctx_data->icp_dev_acquire_info->in_res.format, diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c index 43e08611cd18..0078d61050b9 100644 --- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c +++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c @@ -2875,7 +2875,7 @@ get_dev_handle: req_hdl_param.media_entity_flag = 0; req_hdl_param.ops = ctx->crm_ctx_intf; req_hdl_param.priv = ctx; - + req_hdl_param.dev_id = CAM_ISP; CAM_DBG(CAM_ISP, "get device handle form bridge"); ctx->dev_hdl = cam_create_device_hdl(&req_hdl_param); if (ctx->dev_hdl <= 0) { diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 5f23e87d1c3f..3d394c69368f 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -2637,7 +2637,7 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) /* Stop the master CSID path first */ cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid, - master_base_idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY); + master_base_idx, csid_halt_type); /* stop rest of the CSID paths */ for (i = 0; i < ctx->num_base; i++) { @@ -2647,7 +2647,7 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) ctx->base[i].idx, i, master_base_idx); cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid, - ctx->base[i].idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY); + ctx->base[i].idx, csid_halt_type); } CAM_DBG(CAM_ISP, "Stopping master CID idx %d", master_base_idx); @@ -3575,6 +3575,38 @@ void fill_res_bitmap(uint32_t resource_type, unsigned long *res_bitmap) } } +static int cam_isp_blob_init_frame_drop( + struct cam_isp_init_frame_drop_config *frame_drop_cfg, + struct cam_hw_prepare_update_args *prepare) +{ + struct cam_ife_hw_mgr_ctx *ctx = NULL; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_hw_intf *hw_intf; + uint32_t hw_idx = UINT_MAX; + uint32_t i; + int rc = 0; + + ctx = prepare->ctxt_to_hw_map; + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf->hw_idx == hw_idx) + continue; + + rc = hw_intf->hw_ops.process_cmd(hw_intf->hw_priv, + CAM_IFE_CSID_SET_INIT_FRAME_DROP, + frame_drop_cfg, + sizeof( + struct cam_isp_init_frame_drop_config *)); + hw_idx = hw_intf->hw_idx; + } + } + return rc; +} + static int cam_isp_packet_generic_blob_handler(void *user_data, uint32_t blob_type, uint32_t blob_size, uint8_t *blob_data) { @@ -3709,10 +3741,33 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, } break; case CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG_V2: { - struct cam_isp_bw_config_ab *bw_config_ab = - (struct cam_isp_bw_config_ab *)blob_data; + struct cam_isp_bw_config_ab *bw_config_ab; + struct cam_isp_prepare_hw_update_data *prepare_hw_data; + if (blob_size < sizeof(struct cam_isp_bw_config_ab)) { + CAM_ERR(CAM_ISP, "Invalid blob size %u", blob_size); + return -EINVAL; + } + + bw_config_ab = (struct cam_isp_bw_config_ab *)blob_data; + + if (bw_config_ab->num_rdi > CAM_IFE_RDI_NUM_MAX) { + CAM_ERR(CAM_ISP, "Invalid num_rdi %u in bw config ab", + bw_config_ab->num_rdi); + return -EINVAL; + } + + if (blob_size < (sizeof(uint32_t) * 2 + + (bw_config_ab->num_rdi + 2) + * sizeof(struct cam_isp_bw_vote))) { + CAM_ERR(CAM_ISP, "Invalid blob size %u expected %u", + blob_size, + sizeof(uint32_t) * 2 + + (bw_config_ab->num_rdi + 2) + * sizeof(struct cam_isp_bw_vote)); + return -EINVAL; + } CAM_DBG(CAM_ISP, "AB L:%lld R:%lld usage_type %d", bw_config_ab->left_pix_vote_ab, bw_config_ab->right_pix_vote_ab, @@ -3797,7 +3852,22 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, CAM_ERR(CAM_ISP, "FS Update Failed rc: %d", rc); } break; + case CAM_ISP_GENERIC_BLOB_TYPE_INIT_FRAME_DROP: { + struct cam_isp_init_frame_drop_config *frame_drop_cfg = + (struct cam_isp_init_frame_drop_config *)blob_data; + if (blob_size < sizeof(struct cam_isp_init_frame_drop_config)) { + CAM_ERR(CAM_ISP, "Invalid blob size %u expected %u", + blob_size, + sizeof(struct cam_isp_init_frame_drop_config)); + return -EINVAL; + } + + rc = cam_isp_blob_init_frame_drop(frame_drop_cfg, prepare); + if (rc) + CAM_ERR(CAM_ISP, "Init Frame drop Update Failed"); + } + break; default: CAM_WARN(CAM_ISP, "Invalid blob type %d", blob_type); break; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index ea0b01f39523..f4b91a4d844a 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -468,6 +468,9 @@ static int cam_ife_csid_global_reset(struct cam_ife_csid_hw *csid_hw) csid_hw->hw_intf->hw_idx, val); csid_hw->error_irq_count = 0; + for (i = 0 ; i < CAM_IFE_PIX_PATH_RES_MAX; i++) + csid_hw->res_sof_cnt[i] = 0; + return rc; } @@ -838,7 +841,6 @@ end: return rc; } - static int cam_ife_csid_path_reserve(struct cam_ife_csid_hw *csid_hw, struct cam_csid_hw_reserve_resource_args *reserve) { @@ -953,7 +955,7 @@ static int cam_ife_csid_path_reserve(struct cam_ife_csid_hw *csid_hw, path_data->height = reserve->in_port->height; path_data->start_line = reserve->in_port->line_start; path_data->end_line = reserve->in_port->line_stop; - + path_data->usage_type = reserve->in_port->usage_type; /* Enable RDI crop for single ife use case only */ switch (reserve->res_id) { case CAM_IFE_PIX_PATH_RES_RDI_0: @@ -1120,6 +1122,7 @@ err: static int cam_ife_csid_disable_hw(struct cam_ife_csid_hw *csid_hw) { int rc = -EINVAL; + uint32_t i; struct cam_hw_soc_info *soc_info; const struct cam_ife_csid_reg_offset *csid_reg; unsigned long flags; @@ -1160,12 +1163,95 @@ static int cam_ife_csid_disable_hw(struct cam_ife_csid_hw *csid_hw) spin_lock_irqsave(&csid_hw->lock_state, flags); csid_hw->device_enabled = 0; spin_unlock_irqrestore(&csid_hw->lock_state, flags); + for (i = 0; i < CAM_IFE_PIX_PATH_RES_MAX; i++) + csid_hw->res_sof_cnt[i] = 0; + csid_hw->hw_info->hw_state = CAM_HW_STATE_POWER_DOWN; csid_hw->error_irq_count = 0; return rc; } +static int cam_ife_csid_check_path_active(struct cam_ife_csid_hw *csid_hw) +{ + struct cam_hw_soc_info *soc_info; + const struct cam_ife_csid_reg_offset *csid_reg; + uint32_t i, path_status = 1; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + /* check the IPP path status */ + if (csid_reg->cmn_reg->num_pix) { + path_status = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_status_addr); + CAM_DBG(CAM_ISP, "CSID:%d IPP path status:%d", + csid_hw->hw_intf->hw_idx, path_status); + /* if status is 0 then it is active */ + if (!path_status) + goto end; + } + + if (csid_reg->cmn_reg->num_ppp) { + path_status = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ppp_reg->csid_pxl_status_addr); + CAM_DBG(CAM_ISP, "CSID:%d PPP path status:%d", + csid_hw->hw_intf->hw_idx, path_status); + /* if status is 0 then it is active */ + if (!path_status) + goto end; + } + + /* Check the RDI path status */ + for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) { + path_status = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[i]->csid_rdi_status_addr); + CAM_DBG(CAM_ISP, "CSID:%d RDI:%d path status:%d", + csid_hw->hw_intf->hw_idx, i, path_status); + /* if status is 0 then it is active */ + if (!path_status) + goto end; + } + +end: + return path_status; +} + +static void cam_ife_csid_reset_init_frame_drop( + struct cam_ife_csid_hw *csid_hw) +{ + const struct cam_ife_csid_reg_offset *csid_reg; + uint32_t i = 0; + + /* + * Reset CSID init frame drop value only if all resources are + * released + */ + csid_reg = csid_hw->csid_info->csid_reg; + if (csid_reg->cmn_reg->num_pix) { + if (csid_hw->ipp_res.res_state != + CAM_ISP_RESOURCE_STATE_AVAILABLE) + goto end; + } + + if (csid_reg->cmn_reg->num_ppp) { + if (csid_hw->ppp_res.res_state != + CAM_ISP_RESOURCE_STATE_AVAILABLE) + goto end; + } + + for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) { + if (csid_hw->rdi_res[i].res_state != + CAM_ISP_RESOURCE_STATE_AVAILABLE) + goto end; + } + + /* All CSID resources are available reset the init frame drop */ + csid_hw->init_frame_drop = 0; +end: + return; + +} static int cam_ife_csid_tpg_start(struct cam_ife_csid_hw *csid_hw, struct cam_isp_resource_node *res) @@ -1725,7 +1811,7 @@ static int cam_ife_csid_enable_pxl_path( struct cam_ife_csid_path_cfg *path_data; const struct cam_ife_csid_pxl_reg_offset *pxl_reg = NULL; bool is_ipp; - uint32_t val = 0; + uint32_t val = 0, path_status; path_data = (struct cam_ife_csid_path_cfg *) res->res_priv; csid_reg = csid_hw->csid_info->csid_reg; @@ -1768,14 +1854,15 @@ static int cam_ife_csid_enable_pxl_path( /* Default is internal halt mode */ val = 0; - /* - * Resume at frame boundary if Master or No Sync. - * Slave will get resume command from Master. - */ - if (path_data->sync_mode == CAM_ISP_HW_SYNC_MASTER || - path_data->sync_mode == CAM_ISP_HW_SYNC_NONE) - val |= CAM_CSID_RESUME_AT_FRAME_BOUNDARY; - + /* Resume at frame boundary */ + path_status = cam_ife_csid_check_path_active(csid_hw); + if (!csid_hw->init_frame_drop || + (csid_hw->init_frame_drop && !path_status)) { + CAM_DBG(CAM_ISP, "start pixel path"); + if (path_data->sync_mode == CAM_ISP_HW_SYNC_MASTER || + path_data->sync_mode == CAM_ISP_HW_SYNC_NONE) + val |= CAM_CSID_RESUME_AT_FRAME_BOUNDARY; + } cam_io_w_mb(val, soc_info->reg_map[0].mem_base + pxl_reg->csid_pxl_ctrl_addr); @@ -1789,8 +1876,10 @@ static int cam_ife_csid_enable_pxl_path( if (pxl_reg->ccif_violation_en) val |= CSID_PATH_ERROR_CCIF_VIOLATION; - if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ) + if ((csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ) || + (csid_hw->init_frame_drop && path_status)) val |= CSID_PATH_INFO_INPUT_SOF; + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ) val |= CSID_PATH_INFO_INPUT_EOF; @@ -2087,8 +2176,10 @@ static int cam_ife_csid_enable_rdi_path( { const struct cam_ife_csid_reg_offset *csid_reg; struct cam_hw_soc_info *soc_info; - uint32_t id, val; + struct cam_ife_csid_path_cfg *path_data; + uint32_t id, val, path_status; + path_data = (struct cam_ife_csid_path_cfg *) res->res_priv; csid_reg = csid_hw->csid_info->csid_reg; soc_info = &csid_hw->hw_info->soc_info; id = res->res_id; @@ -2103,19 +2194,28 @@ static int cam_ife_csid_enable_rdi_path( return -EINVAL; } - /*resume at frame boundary */ - cam_io_w_mb(CAM_CSID_RESUME_AT_FRAME_BOUNDARY, - soc_info->reg_map[0].mem_base + - csid_reg->rdi_reg[id]->csid_rdi_ctrl_addr); + if (path_data->usage_type) + path_data->init_frame_drop = csid_hw->init_frame_drop + 1; + /*resume at frame boundary */ + path_status = cam_ife_csid_check_path_active(csid_hw); + if (!path_data->init_frame_drop || + (path_data->init_frame_drop && !path_status)) { + CAM_DBG(CAM_ISP, "Start RDI:%d path", id); + cam_io_w_mb(CAM_CSID_RESUME_AT_FRAME_BOUNDARY, + soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_ctrl_addr); + } /* Enable the required RDI interrupts */ val = CSID_PATH_INFO_RST_DONE | CSID_PATH_ERROR_FIFO_OVERFLOW; if (csid_reg->rdi_reg[id]->ccif_violation_en) val |= CSID_PATH_ERROR_CCIF_VIOLATION; - if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ) + if ((csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ) || + (path_data->init_frame_drop && path_status)) val |= CSID_PATH_INFO_INPUT_SOF; + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ) val |= CSID_PATH_INFO_INPUT_EOF; @@ -2375,6 +2475,19 @@ static int cam_ife_csid_set_csid_debug(struct cam_ife_csid_hw *csid_hw, return 0; } +static int cam_ife_csid_set_init_frame_drop(struct cam_ife_csid_hw *csid_hw, + void *cmd_args) +{ + struct cam_isp_init_frame_drop_config *frame_drop_cfg; + + frame_drop_cfg = (struct cam_isp_init_frame_drop_config *) cmd_args; + csid_hw->init_frame_drop = frame_drop_cfg->init_frame_drop; + CAM_DBG(CAM_ISP, "CSID:%d set init frame drop:%d", + csid_hw->hw_intf->hw_idx, csid_hw->init_frame_drop); + + return 0; +} + static int cam_ife_csid_get_hw_caps(void *hw_priv, void *get_hw_cap_args, uint32_t arg_size) { @@ -2551,6 +2664,7 @@ static int cam_ife_csid_release(void *hw_priv, break; case CAM_ISP_RESOURCE_PIX_PATH: res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + cam_ife_csid_reset_init_frame_drop(csid_hw); break; default: CAM_ERR(CAM_ISP, "CSID:%d Invalid res type:%d res id%d", @@ -3016,6 +3130,9 @@ static int cam_ife_csid_process_cmd(void *hw_priv, case CAM_ISP_HW_CMD_CSID_CLOCK_UPDATE: rc = cam_ife_csid_set_csid_clock(csid_hw, cmd_args); break; + case CAM_IFE_CSID_SET_INIT_FRAME_DROP: + rc = cam_ife_csid_set_init_frame_drop(csid_hw, cmd_args); + break; default: CAM_ERR(CAM_ISP, "CSID:%d unsupported cmd:%d", csid_hw->hw_intf->hw_idx, cmd_type); @@ -3033,6 +3150,9 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) struct cam_hw_soc_info *soc_info; const struct cam_ife_csid_reg_offset *csid_reg; const struct cam_ife_csid_csi2_rx_reg_offset *csi2_reg; + struct cam_ife_csid_path_cfg *path_data; + const struct cam_ife_csid_pxl_reg_offset *pxl_reg; + const struct cam_ife_csid_rdi_reg_offset *rdi_reg; uint32_t i, irq_status_top, irq_status_rx, irq_status_ipp = 0; uint32_t irq_status_rdi[4] = {0, 0, 0, 0}; uint32_t val, irq_status_ppp = 0; @@ -3264,6 +3384,53 @@ handle_fatal_error: csid_hw->irq_debug_cnt++; } + if ((irq_status_ipp & CSID_PATH_INFO_INPUT_SOF) && + (csid_hw->init_frame_drop) && + (csid_hw->ipp_res.res_state == + CAM_ISP_RESOURCE_STATE_STREAMING)) { + csid_hw->res_sof_cnt[CAM_IFE_PIX_PATH_RES_IPP]++; + CAM_DBG(CAM_ISP, + "CSID:%d IPP SOF cnt:%d init_frame_drop:%d", + csid_hw->hw_intf->hw_idx, + csid_hw->res_sof_cnt[CAM_IFE_PIX_PATH_RES_IPP], + csid_hw->init_frame_drop); + if (csid_hw->res_sof_cnt[CAM_IFE_PIX_PATH_RES_IPP] == + csid_hw->init_frame_drop) { + pxl_reg = csid_reg->ipp_reg; + path_data = csid_hw->ipp_res.res_priv; + if (path_data->sync_mode == + CAM_ISP_HW_SYNC_MASTER) { + val = cam_io_r_mb( + soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + + val |= + CAM_CSID_RESUME_AT_FRAME_BOUNDARY; + cam_io_w_mb(val, + soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + + } else if (path_data->sync_mode == + CAM_ISP_HW_SYNC_NONE) { + cam_io_w_mb( + CAM_CSID_RESUME_AT_FRAME_BOUNDARY, + soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + } + + if (!(csid_hw->csid_debug & + CSID_DEBUG_ENABLE_SOF_IRQ)) { + val = cam_io_r_mb( + soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_irq_mask_addr); + val &= ~(CSID_PATH_INFO_INPUT_SOF); + cam_io_w_mb(val, + soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_irq_mask_addr); + } + } + } + if ((irq_status_ipp & CSID_PATH_INFO_INPUT_EOF) && (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ)) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d IPP EOF received", @@ -3299,6 +3466,52 @@ handle_fatal_error: csid_hw->irq_debug_cnt++; } + if ((irq_status_ppp & CSID_PATH_INFO_INPUT_SOF) && + (csid_hw->init_frame_drop) && + (csid_hw->ppp_res.res_state == + CAM_ISP_RESOURCE_STATE_STREAMING)) { + csid_hw->res_sof_cnt[CAM_IFE_PIX_PATH_RES_PPP]++; + CAM_DBG(CAM_ISP, + "CSID:%d PPP SOF cnt:%d init_frame_drop:%d", + csid_hw->hw_intf->hw_idx, + csid_hw->res_sof_cnt[CAM_IFE_PIX_PATH_RES_PPP], + csid_hw->init_frame_drop); + if (csid_hw->res_sof_cnt[CAM_IFE_PIX_PATH_RES_PPP] == + csid_hw->init_frame_drop) { + path_data = csid_hw->ppp_res.res_priv; + pxl_reg = csid_reg->ppp_reg; + if (path_data->sync_mode == + CAM_ISP_HW_SYNC_MASTER) { + val = cam_io_r_mb( + soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + + val |= + CAM_CSID_RESUME_AT_FRAME_BOUNDARY; + cam_io_w_mb(val, + soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + } else if (path_data->sync_mode == + CAM_ISP_HW_SYNC_NONE) { + cam_io_w_mb( + CAM_CSID_RESUME_AT_FRAME_BOUNDARY, + soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + } + + if (!(csid_hw->csid_debug & + CSID_DEBUG_ENABLE_SOF_IRQ)) { + val = cam_io_r_mb( + soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_irq_mask_addr); + val &= ~(CSID_PATH_INFO_INPUT_SOF); + cam_io_w_mb(val, + soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_irq_mask_addr); + } + } + } + if ((irq_status_ppp & CSID_PATH_INFO_INPUT_EOF) && (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ)) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PPP EOF received", @@ -3319,6 +3532,9 @@ handle_fatal_error: } for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) { + path_data = (struct cam_ife_csid_path_cfg *) + csid_hw->rdi_res[i].res_priv; + rdi_reg = csid_reg->rdi_reg[i]; if (irq_status_rdi[i] & BIT(csid_reg->cmn_reg->path_rst_done_shift_val)) { complete(&csid_hw->csid_rdin_complete[i]); @@ -3332,6 +3548,35 @@ handle_fatal_error: csid_hw->irq_debug_cnt++; } + if ((irq_status_rdi[i] & CSID_PATH_INFO_INPUT_SOF) && + (path_data->init_frame_drop) && + (csid_hw->rdi_res[i].res_state == + CAM_ISP_RESOURCE_STATE_STREAMING)) { + csid_hw->res_sof_cnt[i]++; + CAM_DBG(CAM_ISP, + "CSID:%d RDI:%d SOF cnt:%d init_frame_drop:%d", + csid_hw->hw_intf->hw_idx, i, + csid_hw->res_sof_cnt[i], + path_data->init_frame_drop); + if (csid_hw->res_sof_cnt[i] == + path_data->init_frame_drop) { + cam_io_w_mb(CAM_CSID_RESUME_AT_FRAME_BOUNDARY, + soc_info->reg_map[0].mem_base + + rdi_reg->csid_rdi_ctrl_addr); + + if (!(csid_hw->csid_debug & + CSID_DEBUG_ENABLE_SOF_IRQ)) { + val = cam_io_r_mb( + soc_info->reg_map[0].mem_base + + rdi_reg->csid_rdi_irq_mask_addr); + val &= ~(CSID_PATH_INFO_INPUT_SOF); + cam_io_w_mb(val, + soc_info->reg_map[0].mem_base + + rdi_reg->csid_rdi_irq_mask_addr); + } + } + } + if ((irq_status_rdi[i] & CSID_PATH_INFO_INPUT_EOF) && (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ)) CAM_INFO_RATE_LIMIT(CAM_ISP, diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h index 3a093d205f59..600deb245f32 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h @@ -419,6 +419,9 @@ struct cam_ife_csid_cid_data { * @master_idx: For Slave reservation, Give master IFE instance Index. * Slave will synchronize with master Start and stop operations * @clk_rate Clock rate + * @usage_type Usage type ie dual or single ife usecase + * @init_frame_drop init frame drop value. In dual ife case rdi need to drop one + * more frame than pix. * */ struct cam_ife_csid_path_cfg { @@ -437,6 +440,8 @@ struct cam_ife_csid_path_cfg { enum cam_isp_hw_sync_mode sync_mode; uint32_t master_idx; uint64_t clk_rate; + uint32_t usage_type; + uint32_t init_frame_drop; }; /** @@ -468,6 +473,13 @@ struct cam_ife_csid_path_cfg { * @irq_debug_cnt: Counter to track sof irq's when above flag is set. * @error_irq_count Error IRQ count, if continuous error irq comes * need to stop the CSID and mask interrupts. + * @device_enabled Device enabled will set once CSID powered on and + * initial configuration are done. + * @lock_state csid spin lock + * @dual_usage usage type, dual ife or single ife + * @init_frame_drop Initial frame drop number + * @res_sof_cnt path resource sof count value. it used for initial + * frame drop * */ struct cam_ife_csid_hw { @@ -496,6 +508,9 @@ struct cam_ife_csid_hw { uint32_t error_irq_count; uint32_t device_enabled; spinlock_t lock_state; + uint32_t dual_usage; + uint32_t init_frame_drop; + uint32_t res_sof_cnt[CAM_IFE_PIX_PATH_RES_MAX]; }; int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h index 58818fbecf67..0c45bd1268b9 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, 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 @@ -157,6 +157,7 @@ enum cam_ife_csid_cmd_type { CAM_IFE_CSID_CMD_GET_TIME_STAMP, CAM_IFE_CSID_SET_CSID_DEBUG, CAM_IFE_CSID_SOF_IRQ_DEBUG, + CAM_IFE_CSID_SET_INIT_FRAME_DROP, CAM_IFE_CSID_CMD_MAX, }; diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c index 53de02a3a20f..3ffa9e8a2951 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c @@ -251,33 +251,50 @@ int cam_mem_get_cpu_buf(int32_t buf_handle, uintptr_t *vaddr_ptr, size_t *len) if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) return -EINVAL; - if (!tbl.bufq[idx].active) - return -EPERM; + mutex_lock(&tbl.bufq[idx].q_lock); + if (!tbl.bufq[idx].active) { + CAM_ERR(CAM_MEM, "idx: %d not active", idx); + rc = -EPERM; + goto end; + } - if (buf_handle != tbl.bufq[idx].buf_handle) - return -EINVAL; + if (buf_handle != tbl.bufq[idx].buf_handle) { + CAM_ERR(CAM_MEM, "idx: %d Invalid buf handle %d", + idx, buf_handle); + rc = -EINVAL; + goto end; + } - if (!(tbl.bufq[idx].flags & CAM_MEM_FLAG_KMD_ACCESS)) - return -EINVAL; + if (!(tbl.bufq[idx].flags & CAM_MEM_FLAG_KMD_ACCESS)) { + CAM_ERR(CAM_MEM, "idx: %d Invalid flag 0x%x", + idx, tbl.bufq[idx].flags); + rc = -EINVAL; + goto end; + } if (tbl.bufq[idx].kmdvaddr) { dmabuf = tbl.bufq[idx].dma_buf; if (!dmabuf) { CAM_ERR(CAM_MEM, "Invalid DMA buffer pointer"); - return -EINVAL; + rc = -EINVAL; + goto end; } rc = dma_buf_begin_cpu_access(dmabuf, DMA_BIDIRECTIONAL); if (rc) { CAM_ERR(CAM_MEM, "dma begin access failed rc=%d", rc); - return rc; + goto end; } } else { - return -EINVAL; + CAM_ERR(CAM_MEM, "Invalid kmdvaddr"); + rc = -EINVAL; + goto end; } *vaddr_ptr = tbl.bufq[idx].kmdvaddr; *len = tbl.bufq[idx].len; +end: + mutex_unlock(&tbl.bufq[idx].q_lock); return rc; } EXPORT_SYMBOL(cam_mem_get_cpu_buf); @@ -300,30 +317,38 @@ int cam_mem_put_cpu_buf(int32_t buf_handle) if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) return -EINVAL; - if (!tbl.bufq[idx].active) - return -EPERM; + mutex_lock(&tbl.bufq[idx].q_lock); + if (!tbl.bufq[idx].active) { + CAM_ERR(CAM_MEM, "idx: %d not active", idx); + rc = -EPERM; + goto end; + } - if (buf_handle != tbl.bufq[idx].buf_handle) - return -EINVAL; + if (buf_handle != tbl.bufq[idx].buf_handle) { + CAM_ERR(CAM_MEM, "idx: %d Invalid buf handle %d", + idx, buf_handle); + rc = -EINVAL; + goto end; + } dmabuf = tbl.bufq[idx].dma_buf; if (!dmabuf) { CAM_ERR(CAM_CRM, "Invalid DMA buffer pointer"); - return -EINVAL; + rc = -EINVAL; + goto end; } if ((tbl.bufq[idx].flags & CAM_MEM_FLAG_KMD_ACCESS) && (tbl.bufq[idx].kmdvaddr)) { rc = dma_buf_end_cpu_access(dmabuf, DMA_BIDIRECTIONAL); - if (rc) { + if (rc) CAM_ERR(CAM_MEM, "dma begin access failed rc=%d", rc); - return rc; - } } else { CAM_ERR(CAM_MEM, "Invalid buf flag"); rc = -EINVAL; } - +end: + mutex_unlock(&tbl.bufq[idx].q_lock); return rc; } EXPORT_SYMBOL(cam_mem_put_cpu_buf); @@ -953,6 +978,7 @@ static int cam_mem_mgr_cleanup_table(void) tbl.bufq[i].num_hdl = 0; tbl.bufq[i].dma_buf = NULL; tbl.bufq[i].active = false; + tbl.bufq[i].kmdvaddr = 0; mutex_unlock(&tbl.bufq[i].q_lock); mutex_destroy(&tbl.bufq[i].q_lock); } @@ -1051,6 +1077,7 @@ static int cam_mem_util_unmap(int32_t idx, tbl.bufq[idx].len = 0; tbl.bufq[idx].num_hdl = 0; tbl.bufq[idx].active = false; + tbl.bufq[idx].kmdvaddr = 0; mutex_unlock(&tbl.bufq[idx].q_lock); mutex_destroy(&tbl.bufq[idx].q_lock); clear_bit(idx, tbl.bitmap); diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c index 80521ea69deb..9d176678d9de 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c @@ -348,10 +348,12 @@ static void __cam_req_mgr_reset_req_slot(struct cam_req_mgr_core_link *link, struct cam_req_mgr_req_queue *in_q = link->req.in_q; slot = &in_q->slot[idx]; - CAM_DBG(CAM_CRM, "RESET: idx: %d: slot->status %d", idx, slot->status); + CAM_DBG(CAM_CRM, "RESET: last applied idx %d: idx %d: slot->status %d", + in_q->last_applied_idx, idx, slot->status); /* Check if CSL has already pushed new request*/ - if (slot->status == CRM_SLOT_STATUS_REQ_ADDED) + if (slot->status == CRM_SLOT_STATUS_REQ_ADDED || + in_q->last_applied_idx == idx) return; /* Reset input queue slot */ @@ -512,9 +514,11 @@ static int __cam_req_mgr_send_req(struct cam_req_mgr_core_link *link, } if (link->req.apply_data[pd].skip_idx || link->req.apply_data[pd].req_id < 0) { - CAM_DBG(CAM_CRM, "skip %d req_id %lld", + CAM_DBG(CAM_CRM, + "skip %d req_id %lld pd %d dev_name %s", link->req.apply_data[pd].skip_idx, - link->req.apply_data[pd].req_id); + link->req.apply_data[pd].req_id, + pd, dev->dev_info.name); continue; } if (!(dev->dev_info.trigger & trigger)) @@ -893,6 +897,7 @@ static int __cam_req_mgr_check_sync_req_is_ready( int64_t req_id = 0; int sync_slot_idx = 0, sync_rd_idx = 0, rc = 0; int32_t sync_num_slots = 0; + bool ready = true, sync_ready = true; if (!link->sync_link) { CAM_ERR(CAM_CRM, "Sync link null"); @@ -921,17 +926,7 @@ static int __cam_req_mgr_check_sync_req_is_ready( CAM_DBG(CAM_CRM, "Skip Process Req: %lld on link: %x", req_id, link->link_hdl); - link->sync_link_sof_skip = true; - return rc; - } - - rc = __cam_req_mgr_check_link_is_ready(link, slot->idx, true); - if (rc) { - CAM_DBG(CAM_CRM, - "Req: %lld [My link] not ready on link: %x, rc=%d", - req_id, link->link_hdl, rc); - link->sync_link_sof_skip = true; - return rc; + ready = false; } sync_slot_idx = __cam_req_mgr_find_slot_for_req( @@ -939,8 +934,7 @@ static int __cam_req_mgr_check_sync_req_is_ready( if (sync_slot_idx == -1) { CAM_DBG(CAM_CRM, "Req: %lld not found on link: %x [other link]", req_id, sync_link->link_hdl); - link->sync_link_sof_skip = true; - return -EINVAL; + sync_ready = false; } sync_rd_idx = sync_link->req.in_q->rd_idx; @@ -956,14 +950,38 @@ static int __cam_req_mgr_check_sync_req_is_ready( return -EAGAIN; } + rc = __cam_req_mgr_check_link_is_ready(link, slot->idx, true); + if (rc) { + CAM_DBG(CAM_CRM, + "Req: %lld [My link] not ready on link: %x, rc=%d", + req_id, link->link_hdl, rc); + ready = false; + } + rc = __cam_req_mgr_check_link_is_ready(sync_link, sync_slot_idx, true); if (rc && (sync_link->req.in_q->slot[sync_slot_idx].status != CRM_SLOT_STATUS_REQ_APPLIED)) { CAM_DBG(CAM_CRM, "Req: %lld not ready on [other link] link: %x, rc=%d", req_id, sync_link->link_hdl, rc); + sync_ready = false; + } + + /* + * If both of them are ready or not ready, then just + * skip this sof and don't skip sync link next SOF. + */ + if (sync_ready != ready) { + CAM_DBG(CAM_CRM, + "Req: %lld ready %d sync_ready %d, ignore sync link next SOF", + req_id, ready, sync_ready); link->sync_link_sof_skip = true; - return rc; + return -EINVAL; + } else if (ready == false) { + CAM_DBG(CAM_CRM, + "Req: %lld not ready on link: %x", + req_id, link->link_hdl); + return -EINVAL; } CAM_DBG(CAM_REQ, @@ -995,7 +1013,7 @@ static int __cam_req_mgr_check_sync_req_is_ready( static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, uint32_t trigger) { - int rc = 0, idx; + int rc = 0, idx, last_app_idx; int reset_step = 0; struct cam_req_mgr_slot *slot = NULL; struct cam_req_mgr_req_queue *in_q; @@ -1129,6 +1147,7 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, slot->req_id, link->link_hdl); idx = in_q->rd_idx; + reset_step = link->max_delay; if (link->sync_link) { if ((link->in_msync_mode) && @@ -1136,6 +1155,25 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, reset_step = link->sync_link->max_delay; } + + /* This is to handle a rare scenario of scheduling + * issue. If ISP sends multiple sofs due to scheduling + * issue, it is required to retain last applied index + * to help recover. + * In this case, ISP goes into Bubble, asking to reapply + * the bubbled request which has already been reset by + * CRM. Below code retains the last applied request. + */ + + if (slot->req_id > 0) { + last_app_idx = in_q->last_applied_idx; + in_q->last_applied_idx = idx; + if (abs(last_app_idx - idx) >= + reset_step + 1) + __cam_req_mgr_reset_req_slot(link, + last_app_idx); + } + __cam_req_mgr_dec_idx( &idx, reset_step + 1, in_q->num_slots); @@ -2359,18 +2397,24 @@ static struct cam_req_mgr_crm_cb cam_req_mgr_ops = { * */ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link, - struct cam_req_mgr_link_info *link_info) + struct cam_req_mgr_ver_info *link_info) { - int rc = 0, i = 0; + int rc = 0, i = 0, num_devices = 0; struct cam_req_mgr_core_dev_link_setup link_data; struct cam_req_mgr_connected_device *dev; struct cam_req_mgr_req_tbl *pd_tbl; enum cam_pipeline_delay max_delay; uint32_t subscribe_event = 0; - - if (link_info->num_devices > CAM_REQ_MGR_MAX_HANDLES) - return -EPERM; - + if (link_info->version == VERSION_1) { + if (link_info->u.link_info_v1.num_devices > + CAM_REQ_MGR_MAX_HANDLES) + return -EPERM; + } + else if (link_info->version == VERSION_2) { + if (link_info->u.link_info_v2.num_devices > + CAM_REQ_MGR_MAX_HANDLES_V2) + return -EPERM; + } mutex_init(&link->req.lock); CAM_DBG(CAM_CRM, "LOCK_DBG in_q lock %pK", &link->req.lock); link->req.num_tbl = 0; @@ -2380,11 +2424,21 @@ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link, return rc; max_delay = CAM_PIPELINE_DELAY_0; - for (i = 0; i < link_info->num_devices; i++) { + if (link_info->version == VERSION_1) + num_devices = link_info->u.link_info_v1.num_devices; + else if (link_info->version == VERSION_2) + num_devices = link_info->u.link_info_v2.num_devices; + for (i = 0; i < num_devices; i++) { dev = &link->l_dev[i]; /* Using dev hdl, get ops ptr to communicate with device */ - dev->ops = (struct cam_req_mgr_kmd_ops *) - cam_get_device_ops(link_info->dev_hdls[i]); + if (link_info->version == VERSION_1) + dev->ops = (struct cam_req_mgr_kmd_ops *) + cam_get_device_ops( + link_info->u.link_info_v1.dev_hdls[i]); + else if (link_info->version == VERSION_2) + dev->ops = (struct cam_req_mgr_kmd_ops *) + cam_get_device_ops( + link_info->u.link_info_v2.dev_hdls[i]); if (!dev->ops || !dev->ops->get_dev_info || !dev->ops->link_setup) { @@ -2392,18 +2446,29 @@ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link, rc = -ENXIO; goto error; } - dev->dev_hdl = link_info->dev_hdls[i]; + if (link_info->version == VERSION_1) + dev->dev_hdl = link_info->u.link_info_v1.dev_hdls[i]; + else if (link_info->version == VERSION_2) + dev->dev_hdl = link_info->u.link_info_v2.dev_hdls[i]; dev->parent = (void *)link; dev->dev_info.dev_hdl = dev->dev_hdl; rc = dev->ops->get_dev_info(&dev->dev_info); trace_cam_req_mgr_connect_device(link, &dev->dev_info); - - CAM_DBG(CAM_CRM, - "%x: connected: %s, id %d, delay %d, trigger %x", - link_info->session_hdl, dev->dev_info.name, - dev->dev_info.dev_id, dev->dev_info.p_delay, - dev->dev_info.trigger); + if (link_info->version == VERSION_1) + CAM_DBG(CAM_CRM, + "%x: connected: %s, id %d, delay %d, trigger %x", + link_info->u.link_info_v1.session_hdl, + dev->dev_info.name, + dev->dev_info.dev_id, dev->dev_info.p_delay, + dev->dev_info.trigger); + else if (link_info->version == VERSION_2) + CAM_DBG(CAM_CRM, + "%x: connected: %s, id %d, delay %d, trigger %x", + link_info->u.link_info_v2.session_hdl, + dev->dev_info.name, + dev->dev_info.dev_id, dev->dev_info.p_delay, + dev->dev_info.trigger); if (rc < 0 || dev->dev_info.p_delay >= CAM_PIPELINE_DELAY_MAX || @@ -2412,10 +2477,18 @@ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link, CAM_ERR(CAM_CRM, "get device info failed"); goto error; } else { - CAM_DBG(CAM_CRM, "%x: connected: %s, delay %d", - link_info->session_hdl, - dev->dev_info.name, - dev->dev_info.p_delay); + if (link_info->version == VERSION_1) { + CAM_DBG(CAM_CRM, "%x: connected: %s, delay %d", + link_info->u.link_info_v1.session_hdl, + dev->dev_info.name, + dev->dev_info.p_delay); + } + else if (link_info->version == VERSION_2) { + CAM_DBG(CAM_CRM, "%x: connected: %s, delay %d", + link_info->u.link_info_v2.session_hdl, + dev->dev_info.name, + dev->dev_info.p_delay); + } if (dev->dev_info.p_delay > max_delay) max_delay = dev->dev_info.p_delay; @@ -2430,7 +2503,7 @@ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link, link_data.max_delay = max_delay; link_data.subscribe_event = subscribe_event; - for (i = 0; i < link_info->num_devices; i++) { + for (i = 0; i < num_devices; i++) { dev = &link->l_dev[i]; link_data.dev_hdl = dev->dev_hdl; @@ -2473,7 +2546,7 @@ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link, if (link->max_delay < dev->dev_info.p_delay) link->max_delay = dev->dev_info.p_delay; } - link->num_devs = link_info->num_devices; + link->num_devs = num_devices; /* Assign id for pd tables */ __cam_req_mgr_tbl_set_id(link->req.l_tbl, &link->req); @@ -2631,7 +2704,115 @@ end: return rc; } -int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info) +int cam_req_mgr_link(struct cam_req_mgr_ver_info *link_info) +{ + int rc = 0; + int wq_flag = 0; + char buf[128]; + struct cam_create_dev_hdl root_dev; + struct cam_req_mgr_core_session *cam_session; + struct cam_req_mgr_core_link *link; + + if (!link_info) { + CAM_DBG(CAM_CRM, "NULL pointer"); + return -EINVAL; + } + if (link_info->u.link_info_v1.num_devices > CAM_REQ_MGR_MAX_HANDLES) { + CAM_ERR(CAM_CRM, "Invalid num devices %d", + link_info->u.link_info_v1.num_devices); + return -EINVAL; + } + + mutex_lock(&g_crm_core_dev->crm_lock); + + /* session hdl's priv data is cam session struct */ + cam_session = (struct cam_req_mgr_core_session *) + cam_get_device_priv(link_info->u.link_info_v1.session_hdl); + if (!cam_session) { + CAM_DBG(CAM_CRM, "NULL pointer"); + mutex_unlock(&g_crm_core_dev->crm_lock); + return -EINVAL; + } + + /* Allocate link struct and map it with session's request queue */ + link = __cam_req_mgr_reserve_link(cam_session); + if (!link) { + CAM_ERR(CAM_CRM, "failed to reserve new link"); + mutex_unlock(&g_crm_core_dev->crm_lock); + return -EINVAL; + } + CAM_DBG(CAM_CRM, "link reserved %pK %x", link, link->link_hdl); + + memset(&root_dev, 0, sizeof(struct cam_create_dev_hdl)); + root_dev.session_hdl = link_info->u.link_info_v1.session_hdl; + root_dev.priv = (void *)link; + root_dev.dev_id = CAM_CRM; + mutex_lock(&link->lock); + /* Create unique dev handle for link */ + link->link_hdl = cam_create_device_hdl(&root_dev); + if (link->link_hdl < 0) { + CAM_ERR(CAM_CRM, + "Insufficient memory to create new device handle"); + rc = link->link_hdl; + goto link_hdl_fail; + } + link_info->u.link_info_v1.link_hdl = link->link_hdl; + link->last_flush_id = 0; + + /* Allocate memory to hold data of all linked devs */ + rc = __cam_req_mgr_create_subdevs(&link->l_dev, + link_info->u.link_info_v1.num_devices); + if (rc < 0) { + CAM_ERR(CAM_CRM, + "Insufficient memory to create new crm subdevs"); + goto create_subdev_failed; + } + + /* Using device ops query connected devs, prepare request tables */ + rc = __cam_req_mgr_setup_link_info(link, link_info); + if (rc < 0) + goto setup_failed; + + spin_lock_bh(&link->link_state_spin_lock); + link->state = CAM_CRM_LINK_STATE_READY; + spin_unlock_bh(&link->link_state_spin_lock); + + /* Create worker for current link */ + snprintf(buf, sizeof(buf), "%x-%x", + link_info->u.link_info_v1.session_hdl, link->link_hdl); + wq_flag = CAM_WORKQ_FLAG_HIGH_PRIORITY | CAM_WORKQ_FLAG_SERIAL; + rc = cam_req_mgr_workq_create(buf, CRM_WORKQ_NUM_TASKS, + &link->workq, CRM_WORKQ_USAGE_NON_IRQ, wq_flag); + if (rc < 0) { + CAM_ERR(CAM_CRM, "FATAL: unable to create worker"); + __cam_req_mgr_destroy_link_info(link); + goto setup_failed; + } + + /* Assign payload to workqueue tasks */ + rc = __cam_req_mgr_setup_payload(link->workq); + if (rc < 0) { + __cam_req_mgr_destroy_link_info(link); + cam_req_mgr_workq_destroy(&link->workq); + goto setup_failed; + } + + mutex_unlock(&link->lock); + mutex_unlock(&g_crm_core_dev->crm_lock); + return rc; +setup_failed: + __cam_req_mgr_destroy_subdev(link->l_dev); +create_subdev_failed: + cam_destroy_device_hdl(link->link_hdl); + link_info->u.link_info_v1.link_hdl = -1; +link_hdl_fail: + mutex_unlock(&link->lock); + __cam_req_mgr_unreserve_link(cam_session, link); + mutex_unlock(&g_crm_core_dev->crm_lock); + return rc; +} + +int cam_req_mgr_link_v2(struct cam_req_mgr_ver_info *link_info) { int rc = 0; int wq_flag = 0; @@ -2644,9 +2825,10 @@ int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info) CAM_DBG(CAM_CRM, "NULL pointer"); return -EINVAL; } - if (link_info->num_devices > CAM_REQ_MGR_MAX_HANDLES) { + if (link_info->u.link_info_v2.num_devices > + CAM_REQ_MGR_MAX_HANDLES_V2) { CAM_ERR(CAM_CRM, "Invalid num devices %d", - link_info->num_devices); + link_info->u.link_info_v2.num_devices); return -EINVAL; } @@ -2654,7 +2836,7 @@ int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info) /* session hdl's priv data is cam session struct */ cam_session = (struct cam_req_mgr_core_session *) - cam_get_device_priv(link_info->session_hdl); + cam_get_device_priv(link_info->u.link_info_v2.session_hdl); if (!cam_session) { CAM_DBG(CAM_CRM, "NULL pointer"); mutex_unlock(&g_crm_core_dev->crm_lock); @@ -2671,7 +2853,7 @@ int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info) CAM_DBG(CAM_CRM, "link reserved %pK %x", link, link->link_hdl); memset(&root_dev, 0, sizeof(struct cam_create_dev_hdl)); - root_dev.session_hdl = link_info->session_hdl; + root_dev.session_hdl = link_info->u.link_info_v2.session_hdl; root_dev.priv = (void *)link; mutex_lock(&link->lock); @@ -2683,12 +2865,12 @@ int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info) rc = link->link_hdl; goto link_hdl_fail; } - link_info->link_hdl = link->link_hdl; + link_info->u.link_info_v2.link_hdl = link->link_hdl; link->last_flush_id = 0; /* Allocate memory to hold data of all linked devs */ rc = __cam_req_mgr_create_subdevs(&link->l_dev, - link_info->num_devices); + link_info->u.link_info_v2.num_devices); if (rc < 0) { CAM_ERR(CAM_CRM, "Insufficient memory to create new crm subdevs"); @@ -2706,7 +2888,7 @@ int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info) /* Create worker for current link */ snprintf(buf, sizeof(buf), "%x-%x", - link_info->session_hdl, link->link_hdl); + link_info->u.link_info_v2.session_hdl, link->link_hdl); wq_flag = CAM_WORKQ_FLAG_HIGH_PRIORITY | CAM_WORKQ_FLAG_SERIAL; rc = cam_req_mgr_workq_create(buf, CRM_WORKQ_NUM_TASKS, &link->workq, CRM_WORKQ_USAGE_NON_IRQ, wq_flag); @@ -2731,7 +2913,7 @@ setup_failed: __cam_req_mgr_destroy_subdev(link->l_dev); create_subdev_failed: cam_destroy_device_hdl(link->link_hdl); - link_info->link_hdl = -1; + link_info->u.link_info_v2.link_hdl = -1; link_hdl_fail: mutex_unlock(&link->lock); __cam_req_mgr_unreserve_link(cam_session, link); @@ -2739,6 +2921,7 @@ link_hdl_fail: return rc; } + int cam_req_mgr_unlink(struct cam_req_mgr_unlink_info *unlink_info) { int rc = 0; diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h index 26f5426b67b0..7bd04c137ed9 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h @@ -36,6 +36,9 @@ #define MAXIMUM_LINKS_PER_SESSION 4 +#define VERSION_1 1 +#define VERSION_2 2 + /** * enum crm_workq_task_type * @codes: to identify which type of task is present @@ -233,12 +236,14 @@ struct cam_req_mgr_slot { * @slot : request slot holding incoming request id and bubble info. * @rd_idx : indicates slot index currently in process. * @wr_idx : indicates slot index to hold new upcoming req. + * @last_applied_idx : indicates slot index last applied successfully. */ struct cam_req_mgr_req_queue { int32_t num_slots; struct cam_req_mgr_slot slot[MAX_REQ_SLOTS]; int32_t rd_idx; int32_t wr_idx; + int32_t last_applied_idx; }; /** @@ -410,7 +415,9 @@ int cam_req_mgr_destroy_session(struct cam_req_mgr_session_info *ses_info); * a unique link handle for the link and is specific to a * session. Returns link handle */ -int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info); +int cam_req_mgr_link(struct cam_req_mgr_ver_info *link_info); +int cam_req_mgr_link_v2(struct cam_req_mgr_ver_info *link_info); + /** * cam_req_mgr_unlink() diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c index 5cf1d844f5e2..31607ac6391f 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2019, 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 @@ -268,27 +268,50 @@ static long cam_private_ioctl(struct file *file, void *fh, break; case CAM_REQ_MGR_LINK: { - struct cam_req_mgr_link_info link_info; + struct cam_req_mgr_ver_info ver_info; - if (k_ioctl->size != sizeof(link_info)) + if (k_ioctl->size != sizeof(ver_info.u.link_info_v1)) return -EINVAL; - if (copy_from_user(&link_info, + if (copy_from_user(&ver_info.u.link_info_v1, u64_to_user_ptr(k_ioctl->handle), sizeof(struct cam_req_mgr_link_info))) { return -EFAULT; } - - rc = cam_req_mgr_link(&link_info); + ver_info.version = VERSION_1; + rc = cam_req_mgr_link(&ver_info); if (!rc) if (copy_to_user( u64_to_user_ptr(k_ioctl->handle), - &link_info, + &ver_info.u.link_info_v1, sizeof(struct cam_req_mgr_link_info))) rc = -EFAULT; } break; + case CAM_REQ_MGR_LINK_V2: { + struct cam_req_mgr_ver_info ver_info; + + if (k_ioctl->size != sizeof(ver_info.u.link_info_v2)) + return -EINVAL; + + if (copy_from_user(&ver_info.u.link_info_v2, + u64_to_user_ptr(k_ioctl->handle), + sizeof(struct cam_req_mgr_link_info_v2))) { + return -EFAULT; + } + ver_info.version = VERSION_2; + rc = cam_req_mgr_link_v2(&ver_info); + if (!rc) + if (copy_to_user( + u64_to_user_ptr(k_ioctl->handle), + &ver_info.u.link_info_v2, + sizeof(struct + cam_req_mgr_link_info_v2))) + rc = -EFAULT; + } + break; + case CAM_REQ_MGR_UNLINK: { struct cam_req_mgr_unlink_info unlink_info; diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.c index dda04f8e5164..d531fdcf388b 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.c +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, 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 @@ -128,6 +128,21 @@ static int32_t cam_get_free_handle_index(void) return idx; } +void cam_dump_tbl_info(void) +{ + int i; + + for (i = 0; i < CAM_REQ_MGR_MAX_HANDLES; i++) + CAM_INFO(CAM_CRM, "session_hdl=%x hdl_value=%x\n" + "type=%d state=%d dev_id=%lld", + hdl_tbl->hdl[i].session_hdl, + hdl_tbl->hdl[i].hdl_value, + hdl_tbl->hdl[i].type, + hdl_tbl->hdl[i].state, + hdl_tbl->hdl[i].dev_id); + +} + int32_t cam_create_session_hdl(void *priv) { int idx; @@ -144,6 +159,7 @@ int32_t cam_create_session_hdl(void *priv) idx = cam_get_free_handle_index(); if (idx < 0) { CAM_ERR(CAM_CRM, "Unable to create session handle"); + cam_dump_tbl_info(); spin_unlock_bh(&hdl_tbl_lock); return idx; } @@ -177,6 +193,7 @@ int32_t cam_create_device_hdl(struct cam_create_dev_hdl *hdl_data) idx = cam_get_free_handle_index(); if (idx < 0) { CAM_ERR(CAM_CRM, "Unable to create device handle"); + cam_dump_tbl_info(); spin_unlock_bh(&hdl_tbl_lock); return idx; } @@ -189,6 +206,7 @@ int32_t cam_create_device_hdl(struct cam_create_dev_hdl *hdl_data) hdl_tbl->hdl[idx].state = HDL_ACTIVE; hdl_tbl->hdl[idx].priv = hdl_data->priv; hdl_tbl->hdl[idx].ops = hdl_data->ops; + hdl_tbl->hdl[idx].dev_id = hdl_data->dev_id; spin_unlock_bh(&hdl_tbl_lock); pr_debug("%s: handle = %x", __func__, handle); diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.h index 7b8e3e601ed8..50d6f309da15 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.h +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2019, 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 @@ -50,6 +50,7 @@ struct handle { uint32_t hdl_value; enum hdl_type type; enum hdl_state state; + uint64_t dev_id; void *ops; void *priv; }; @@ -80,6 +81,7 @@ struct cam_create_dev_hdl { int32_t v4l2_sub_dev_flag; int32_t media_entity_flag; int32_t reserved; + uint64_t dev_id; void *ops; void *priv; }; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c index f6f562c79093..3bdc0f5e0b9f 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, 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 @@ -786,7 +786,7 @@ int32_t cam_actuator_driver_cmd(struct cam_actuator_ctrl_t *a_ctrl, bridge_params.v4l2_sub_dev_flag = 0; bridge_params.media_entity_flag = 0; bridge_params.priv = a_ctrl; - + bridge_params.dev_id = CAM_ACTUATOR; actuator_acq_dev.device_handle = cam_create_device_hdl(&bridge_params); a_ctrl->bridge_intf.device_hdl = actuator_acq_dev.device_handle; 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 ed88282737c0..a06a4c6c6339 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 @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, 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 @@ -1094,7 +1094,7 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd, * RD_DONE exclusively. */ rem_jiffies = wait_for_completion_timeout( - &cci_dev->cci_master_info[master].reset_complete, + &cci_dev->cci_master_info[master].rd_done, CCI_TIMEOUT); if (!rem_jiffies) { rc = -ETIMEDOUT; @@ -1275,10 +1275,11 @@ static int32_t cam_cci_read(struct v4l2_subdev *sd, val = 1 << ((master * 2) + queue); cam_io_w_mb(val, base + CCI_QUEUE_START_ADDR); CAM_DBG(CAM_CCI, - "waiting_for_rd_done [exp_words: %d]", exp_words); + "waiting_for_rd_done [exp_words: %d]", + ((read_cfg->num_byte / 4) + 1)); rc = wait_for_completion_timeout( - &cci_dev->cci_master_info[master].reset_complete, CCI_TIMEOUT); + &cci_dev->cci_master_info[master].rd_done, CCI_TIMEOUT); if (rc <= 0) { #ifdef DUMP_CCI_REGISTERS cam_cci_dump_registers(cci_dev, master, queue); @@ -1692,14 +1693,19 @@ int32_t cam_cci_core_cfg(struct v4l2_subdev *sd, struct cam_cci_ctrl *cci_ctrl) { int32_t rc = 0; - + struct cci_device *cci_dev = v4l2_get_subdevdata(sd); CAM_DBG(CAM_CCI, "cmd %d", cci_ctrl->cmd); + switch (cci_ctrl->cmd) { case MSM_CCI_INIT: + mutex_lock(&cci_dev->init_mutex); rc = cam_cci_init(sd, cci_ctrl); + mutex_unlock(&cci_dev->init_mutex); break; case MSM_CCI_RELEASE: + mutex_lock(&cci_dev->init_mutex); rc = cam_cci_release(sd); + mutex_unlock(&cci_dev->init_mutex); break; case MSM_CCI_I2C_READ: rc = cam_cci_read_bytes(sd, cci_ctrl); diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c index 6ac042c83604..69b5af002610 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, 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 @@ -71,20 +71,26 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) irq_status0 = cam_io_r_mb(base + CCI_IRQ_STATUS_0_ADDR); irq_status1 = cam_io_r_mb(base + CCI_IRQ_STATUS_1_ADDR); + CAM_DBG(CAM_CCI, "BASE: %pK", base); CAM_DBG(CAM_CCI, "irq0:%x irq1:%x", irq_status0, irq_status1); if (irq_status0 & CCI_IRQ_STATUS_0_RST_DONE_ACK_BMSK) { + struct cam_cci_master_info *cci_master_info; if (cci_dev->cci_master_info[MASTER_0].reset_pending == TRUE) { + cci_master_info = &cci_dev->cci_master_info[MASTER_0]; cci_dev->cci_master_info[MASTER_0].reset_pending = FALSE; - complete( - &cci_dev->cci_master_info[MASTER_0].reset_complete); + if (!cci_master_info->status) + complete(&cci_master_info->reset_complete); + cci_master_info->status = 0; } if (cci_dev->cci_master_info[MASTER_1].reset_pending == TRUE) { + cci_master_info = &cci_dev->cci_master_info[MASTER_1]; cci_dev->cci_master_info[MASTER_1].reset_pending = FALSE; - complete( - &cci_dev->cci_master_info[MASTER_1].reset_complete); + if (!cci_master_info->status) + complete(&cci_master_info->reset_complete); + cci_master_info->status = 0; } } @@ -93,7 +99,7 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) cci_dev->cci_master_info[MASTER_0].status = 0; rd_done_th_assert = true; complete(&cci_dev->cci_master_info[MASTER_0].th_complete); - complete(&cci_dev->cci_master_info[MASTER_0].reset_complete); + complete(&cci_dev->cci_master_info[MASTER_0].rd_done); } if ((irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK) && (!rd_done_th_assert)) { @@ -102,7 +108,7 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) if (cci_dev->is_burst_read) complete( &cci_dev->cci_master_info[MASTER_0].th_complete); - complete(&cci_dev->cci_master_info[MASTER_0].reset_complete); + complete(&cci_dev->cci_master_info[MASTER_0].rd_done); } if ((irq_status1 & CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD) && (!rd_done_th_assert)) { @@ -149,7 +155,7 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) cci_dev->cci_master_info[MASTER_1].status = 0; rd_done_th_assert = true; complete(&cci_dev->cci_master_info[MASTER_1].th_complete); - complete(&cci_dev->cci_master_info[MASTER_1].reset_complete); + complete(&cci_dev->cci_master_info[MASTER_1].rd_done); } if ((irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK) && (!rd_done_th_assert)) { @@ -158,7 +164,7 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) if (cci_dev->is_burst_read) complete( &cci_dev->cci_master_info[MASTER_1].th_complete); - complete(&cci_dev->cci_master_info[MASTER_1].reset_complete); + complete(&cci_dev->cci_master_info[MASTER_1].rd_done); } if ((irq_status1 & CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD) && (!rd_done_th_assert)) { @@ -217,16 +223,33 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) } if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK) { cci_dev->cci_master_info[MASTER_0].status = -EINVAL; - cam_io_w_mb(CCI_M0_HALT_REQ_RMSK, - base + CCI_HALT_REQ_ADDR); - CAM_DBG(CAM_CCI, "MASTER_0 error 0x%x", irq_status0); + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_NACK_ERROR_BMSK) + CAM_ERR(CAM_CCI, "Base:%pK, M0 NACK ERROR: 0x%x", + base, irq_status0); + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_ERROR_BMSK) + CAM_ERR(CAM_CCI, + "Base:%pK, M0 QUEUE_OVER/UNDER_FLOW OR CMD ERR: 0x%x", + base, irq_status0); + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_RD_ERROR_BMSK) + CAM_ERR(CAM_CCI, + "Base: %pK, M0 RD_OVER/UNDER_FLOW ERROR: 0x%x", + base, irq_status0); + cam_io_w_mb(CCI_M0_HALT_REQ_RMSK, base + CCI_HALT_REQ_ADDR); } if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK) { cci_dev->cci_master_info[MASTER_1].status = -EINVAL; - cam_io_w_mb(CCI_M1_HALT_REQ_RMSK, - base + CCI_HALT_REQ_ADDR); - CAM_DBG(CAM_CCI, "MASTER_1 error 0x%x", irq_status0); - + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_NACK_ERROR_BMSK) + CAM_ERR(CAM_CCI, "Base:%pK, M1 NACK ERROR: 0x%x", + base, irq_status0); + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_ERROR_BMSK) + CAM_ERR(CAM_CCI, + "Base:%pK, M1 QUEUE_OVER_UNDER_FLOW OR CMD ERROR:0x%x", + base, irq_status0); + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_RD_ERROR_BMSK) + CAM_ERR(CAM_CCI, + "Base:%pK, M1 RD_OVER/UNDER_FLOW ERROR: 0x%x", + base, irq_status0); + cam_io_w_mb(CCI_M1_HALT_REQ_RMSK, base + CCI_HALT_REQ_ADDR); } cam_io_w_mb(irq_status0, base + CCI_IRQ_CLEAR_0_ADDR); @@ -402,7 +425,8 @@ static int cam_cci_platform_probe(struct platform_device *pdev) } g_cci_subdev[soc_info->index] = &new_cci_dev->v4l2_dev_str.sd; - CAM_ERR(CAM_CCI, "Device Type :%d", soc_info->index); + mutex_init(&(new_cci_dev->init_mutex)); + CAM_INFO(CAM_CCI, "Device Type :%d", soc_info->index); cam_register_subdev_fops(&cci_v4l2_subdev_fops); cci_v4l2_subdev_fops.unlocked_ioctl = cam_cci_subdev_fops_ioctl; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h index 83c935b52885..2e4c032cb322 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, 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 @@ -140,6 +140,7 @@ struct cam_cci_master_info { uint8_t reset_pending; struct mutex mutex; struct completion reset_complete; + struct completion rd_done; struct completion th_complete; struct mutex mutex_q[NUM_QUEUES]; struct completion report_q[NUM_QUEUES]; @@ -172,40 +173,41 @@ enum cam_cci_state_t { /** * struct cci_device - * @pdev: Platform device - * @subdev: V4L2 sub device - * @base: Base address of CCI device - * @hw_version: Hardware version - * @ref_count: Reference Count - * @cci_state: CCI state machine - * @num_clk: Number of CCI clock - * @cci_clk: CCI clock structure - * @cci_clk_info: CCI clock information - * @cam_cci_i2c_queue_info: CCI queue information - * @i2c_freq_mode: I2C frequency of operations - * @cci_clk_params: CCI hw clk params - * @cci_gpio_tbl: CCI GPIO table - * @cci_gpio_tbl_size: GPIO table size - * @cci_pinctrl: Pinctrl structure - * @cci_pinctrl_status: CCI pinctrl status - * @cci_clk_src: CCI clk src rate - * @cci_vreg: CCI regulator structure - * @cci_reg_ptr: CCI individual regulator structure - * @regulator_count: Regulator count - * @support_seq_write: - * Set this flag when sequential write is enabled - * @write_wq: Work queue structure - * @valid_sync: Is it a valid sync with CSID - * @v4l2_dev_str: V4L2 device structure - * @cci_wait_sync_cfg: CCI sync config - * @cycles_per_us: Cycles per micro sec - * @payload_size: CCI packet payload size - * @irq_status1: Store irq_status1 to be cleared after - * draining FIFO buffer for burst read - * @lock_status: to protect changes to irq_status1 - * @is_burst_read: Flag to determine if we are performing - * a burst read operation or not - * @irqs_disabled: Mask for IRQs that are disabled + * @pdev: Platform device + * @subdev: V4L2 sub device + * @base: Base address of CCI device + * @hw_version: Hardware version + * @ref_count: Reference Count + * @cci_state: CCI state machine + * @num_clk: Number of CCI clock + * @cci_clk: CCI clock structure + * @cci_clk_info: CCI clock information + * @cam_cci_i2c_queue_info: CCI queue information + * @i2c_freq_mode: I2C frequency of operations + * @cci_clk_params: CCI hw clk params + * @cci_gpio_tbl: CCI GPIO table + * @cci_gpio_tbl_size: GPIO table size + * @cci_pinctrl: Pinctrl structure + * @cci_pinctrl_status: CCI pinctrl status + * @cci_clk_src: CCI clk src rate + * @cci_vreg: CCI regulator structure + * @cci_reg_ptr: CCI individual regulator structure + * @regulator_count: Regulator count + * @support_seq_write: Set this flag when sequential write is enabled + * @write_wq: Work queue structure + * @valid_sync: Is it a valid sync with CSID + * @v4l2_dev_str: V4L2 device structure + * @cci_wait_sync_cfg: CCI sync config + * @cycles_per_us: Cycles per micro sec + * @payload_size: CCI packet payload size + * @irq_status1: Store irq_status1 to be cleared after + * draining FIFO buffer for burst read + * @lock_status: to protect changes to irq_status1 + * @is_burst_read: Flag to determine if we are performing + * a burst read operation or not + * @irqs_disabled: Mask for IRQs that are disabled + * @init_mutex: Mutex for maintaining refcount for attached + * devices to cci during init/deinit. */ struct cci_device { struct v4l2_subdev subdev; @@ -234,6 +236,7 @@ struct cci_device { spinlock_t lock_status; bool is_burst_read; uint32_t irqs_disabled; + struct mutex init_mutex; }; enum cam_cci_i2c_cmd_type { diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_hwreg.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_hwreg.h index 027a0501dcae..ead18afc77ad 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_hwreg.h +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_hwreg.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2015, 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2015, 2017-2019, 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 @@ -61,6 +61,12 @@ #define CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT_BMSK 0x10 #define CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK 0x18000EE6 #define CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK 0x60EE6000 +#define CCI_IRQ_STATUS_0_I2C_M0_NACK_ERROR_BMSK 0x18000000 +#define CCI_IRQ_STATUS_0_I2C_M1_NACK_ERROR_BMSK 0x60000000 +#define CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_ERROR_BMSK 0xEE0 +#define CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_ERROR_BMSK 0xEE0000 +#define CCI_IRQ_STATUS_0_I2C_M0_RD_ERROR_BMSK 0x6 +#define CCI_IRQ_STATUS_0_I2C_M1_RD_ERROR_BMSK 0x6000 #define CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK 0x1 #define CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD 0x10000 #define CCI_IRQ_STATUS_1_I2C_M0_RD_PAUSE 0x20000 diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_soc.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_soc.c index fa290c0b982c..0181a4d8e2ff 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_soc.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_soc.c @@ -19,7 +19,7 @@ int cam_cci_init(struct v4l2_subdev *sd, uint8_t i = 0, j = 0; int32_t rc = 0; struct cci_device *cci_dev; - enum cci_i2c_master_t master = MASTER_0; + enum cci_i2c_master_t master = c_ctrl->cci_info->cci_i2c_master; struct cam_ahb_vote ahb_vote; struct cam_axi_vote axi_vote; struct cam_hw_soc_info *soc_info = NULL; @@ -47,7 +47,6 @@ int cam_cci_init(struct v4l2_subdev *sd, if (cci_dev->ref_count++) { CAM_DBG(CAM_CCI, "ref_count %d", cci_dev->ref_count); - master = c_ctrl->cci_info->cci_i2c_master; CAM_DBG(CAM_CCI, "master %d", master); if (master < MASTER_MAX && master >= 0) { mutex_lock(&cci_dev->cci_master_info[master].mutex); @@ -55,6 +54,8 @@ int cam_cci_init(struct v4l2_subdev *sd, /* Re-initialize the completion */ reinit_completion( &cci_dev->cci_master_info[master].reset_complete); + reinit_completion( + &cci_dev->cci_master_info[master].rd_done); for (i = 0; i < NUM_QUEUES; i++) reinit_completion( &cci_dev->cci_master_info[master].report_q[i]); @@ -93,6 +94,7 @@ int cam_cci_init(struct v4l2_subdev *sd, /* Re-initialize the completion */ reinit_completion(&cci_dev->cci_master_info[master].reset_complete); + reinit_completion(&cci_dev->cci_master_info[master].rd_done); for (i = 0; i < NUM_QUEUES; i++) reinit_completion( &cci_dev->cci_master_info[master].report_q[i]); @@ -128,12 +130,12 @@ int cam_cci_init(struct v4l2_subdev *sd, } } - cci_dev->cci_master_info[MASTER_0].reset_pending = TRUE; + cci_dev->cci_master_info[master].reset_pending = TRUE; cam_io_w_mb(CCI_RESET_CMD_RMSK, base + CCI_RESET_CMD_ADDR); cam_io_w_mb(0x1, base + CCI_RESET_CMD_ADDR); rc = wait_for_completion_timeout( - &cci_dev->cci_master_info[MASTER_0].reset_complete, + &cci_dev->cci_master_info[master].reset_complete, CCI_TIMEOUT); if (rc <= 0) { CAM_ERR(CAM_CCI, "wait_for_completion_timeout"); @@ -205,6 +207,8 @@ static void cam_cci_init_cci_params(struct cci_device *new_cci_dev) &new_cci_dev->cci_master_info[i].reset_complete); init_completion( &new_cci_dev->cci_master_info[i].th_complete); + init_completion( + &new_cci_dev->cci_master_info[i].rd_done); for (j = 0; j < NUM_QUEUES; j++) { mutex_init(&new_cci_dev->cci_master_info[i].mutex_q[j]); diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c index 5304b463f7ab..57f0d0b58288 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c @@ -725,7 +725,7 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, bridge_params.v4l2_sub_dev_flag = 0; bridge_params.media_entity_flag = 0; bridge_params.priv = csiphy_dev; - + bridge_params.dev_id = CAM_CSIPHY; if (csiphy_acq_params.combo_mode >= 2) { CAM_ERR(CAM_CSIPHY, "Invalid combo_mode %d", csiphy_acq_params.combo_mode); diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h index 67653e81fde1..edde07091d9e 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h @@ -21,7 +21,7 @@ struct csiphy_reg_parms_t csiphy_v1_2 = { .mipi_csiphy_glbl_irq_cmd_addr = 0x828, .csiphy_common_array_size = 6, .csiphy_reset_array_size = 5, - .csiphy_2ph_config_array_size = 21, + .csiphy_2ph_config_array_size = 22, .csiphy_3ph_config_array_size = 38, .csiphy_2ph_clock_lane = 0x1, .csiphy_2ph_combo_ck_ln = 0x10, @@ -78,10 +78,11 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0008, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -105,6 +106,7 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x070c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -128,6 +130,7 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x020c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -151,6 +154,7 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x040c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -174,6 +178,7 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x060c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, }; @@ -197,10 +202,11 @@ struct csiphy_reg_t {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0008, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -224,6 +230,7 @@ struct csiphy_reg_t {0x070c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -247,6 +254,7 @@ struct csiphy_reg_t {0x020c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -270,6 +278,7 @@ struct csiphy_reg_t {0x040c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -293,6 +302,7 @@ struct csiphy_reg_t {0x060c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, }; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c index 209daa2064d9..57aa7955a6db 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c @@ -356,7 +356,7 @@ static int32_t cam_eeprom_get_dev_handle(struct cam_eeprom_ctrl_t *e_ctrl, bridge_params.v4l2_sub_dev_flag = 0; bridge_params.media_entity_flag = 0; bridge_params.priv = e_ctrl; - + bridge_params.dev_id = CAM_EEPROM; eeprom_acq_dev.device_handle = cam_create_device_hdl(&bridge_params); e_ctrl->bridge_intf.device_hdl = eeprom_acq_dev.device_handle; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c index 1a0edb8d4d02..f4c9d254df7c 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c @@ -71,7 +71,7 @@ static int32_t cam_flash_driver_cmd(struct cam_flash_ctrl *fctrl, bridge_params.v4l2_sub_dev_flag = 0; bridge_params.media_entity_flag = 0; bridge_params.priv = fctrl; - + bridge_params.dev_id = CAM_FLASH; flash_acq_dev.device_handle = cam_create_device_hdl(&bridge_params); fctrl->bridge_intf.device_hdl = diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c index 8f8ddca8c668..937c46ab5033 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, 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 @@ -90,7 +90,7 @@ static int cam_ois_get_dev_handle(struct cam_ois_ctrl_t *o_ctrl, bridge_params.v4l2_sub_dev_flag = 0; bridge_params.media_entity_flag = 0; bridge_params.priv = o_ctrl; - + bridge_params.dev_id = CAM_OIS; ois_acq_dev.device_handle = cam_create_device_hdl(&bridge_params); o_ctrl->bridge_intf.device_hdl = ois_acq_dev.device_handle; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c index 7c44aaa4ccec..36db52249f47 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -776,7 +776,7 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, bridge_params.v4l2_sub_dev_flag = 0; bridge_params.media_entity_flag = 0; bridge_params.priv = s_ctrl; - + bridge_params.dev_id = CAM_SENSOR; sensor_acq_dev.device_handle = cam_create_device_hdl(&bridge_params); s_ctrl->bridge_intf.device_hdl = sensor_acq_dev.device_handle; 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 8ba6deb54fbc..7df30337e2ec 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 @@ -23,7 +23,7 @@ static char supported_clk_info[256]; static char debugfs_dir_name[64]; static int cam_soc_util_get_clk_level(struct cam_hw_soc_info *soc_info, - int32_t src_clk_idx, int32_t clk_rate) + int32_t src_clk_idx, int64_t clk_rate) { int i; long clk_rate_round; @@ -38,7 +38,7 @@ static int cam_soc_util_get_clk_level(struct cam_hw_soc_info *soc_info, for (i = 0; i < CAM_MAX_VOTE; i++) { if (soc_info->clk_rate[i][src_clk_idx] >= clk_rate_round) { CAM_DBG(CAM_UTIL, - "soc = %d round rate = %ld actual = %d", + "soc = %d round rate = %ld actual = %lld", soc_info->clk_rate[i][src_clk_idx], clk_rate_round, clk_rate); return i; @@ -387,7 +387,7 @@ int cam_soc_util_set_clk_flags(struct cam_hw_soc_info *soc_info, * @return: Success or failure */ static int cam_soc_util_set_clk_rate(struct clk *clk, const char *clk_name, - int32_t clk_rate) + int64_t clk_rate) { int rc = 0; long clk_rate_round; @@ -395,7 +395,7 @@ static int cam_soc_util_set_clk_rate(struct clk *clk, const char *clk_name, if (!clk || !clk_name) return -EINVAL; - CAM_DBG(CAM_UTIL, "set %s, rate %d", clk_name, clk_rate); + CAM_DBG(CAM_UTIL, "set %s, rate %lld", clk_name, clk_rate); if (clk_rate > 0) { clk_rate_round = clk_round_rate(clk, clk_rate); CAM_DBG(CAM_UTIL, "new_rate %ld", clk_rate_round); @@ -431,7 +431,7 @@ static int cam_soc_util_set_clk_rate(struct clk *clk, const char *clk_name, } int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, - int32_t clk_rate) + int64_t clk_rate) { int32_t src_clk_idx; struct clk *clk = NULL; @@ -452,7 +452,7 @@ int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, if (soc_info->cam_cx_ipeak_enable && clk_rate >= 0) { apply_level = cam_soc_util_get_clk_level(soc_info, src_clk_idx, clk_rate); - CAM_DBG(CAM_UTIL, "set %s, rate %d dev_name = %s\n" + CAM_DBG(CAM_UTIL, "set %s, rate %lld dev_name = %s\n" "apply level = %d", soc_info->clk_name[src_clk_idx], clk_rate, soc_info->dev_name, apply_level); 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 0ee8445c0129..d0bab027790e 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 @@ -390,7 +390,7 @@ int cam_soc_util_set_clk_flags(struct cam_hw_soc_info *soc_info, * @return: success or failure */ int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, - int32_t clk_rate); + int64_t clk_rate); /** * cam_soc_util_get_option_clk_by_name() diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index 225af295a7c5..faf8d6f28d9d 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.c @@ -44,6 +44,7 @@ #define FIRMWARE_SIZE 0X00A00000 #define REG_ADDR_OFFSET_BITMASK 0x000FFFFF #define QDSS_IOVA_START 0x80001000 +#define MIN_PAYLOAD_SIZE 3 static struct hal_device_data hal_ctxt; @@ -3464,22 +3465,50 @@ static void __flush_debug_queue(struct venus_hfi_device *device, u8 *packet) log_level = VIDC_ERR; } +#define SKIP_INVALID_PKT(pkt_size, payload_size, pkt_hdr_size) ({ \ + if (pkt_size < pkt_hdr_size || \ + payload_size < MIN_PAYLOAD_SIZE || \ + payload_size > \ + (pkt_size - pkt_hdr_size + sizeof(u8))) { \ + dprintk(VIDC_ERR, \ + "%s: invalid msg size - %d\n", \ + __func__, pkt->msg_size); \ + continue; \ + } \ + }) + while (!__iface_dbgq_read(device, packet)) { - struct hfi_msg_sys_coverage_packet *pkt = - (struct hfi_msg_sys_coverage_packet *) packet; + struct hfi_packet_header *pkt = + (struct hfi_packet_header *) packet; + + if (pkt->size < sizeof(struct hfi_packet_header)) { + dprintk(VIDC_ERR, "Invalid pkt size - %s\n", + __func__); + continue; + } if (pkt->packet_type == HFI_MSG_SYS_COV) { + struct hfi_msg_sys_coverage_packet *pkt = + (struct hfi_msg_sys_coverage_packet *) packet; int stm_size = 0; + SKIP_INVALID_PKT(pkt->size, + pkt->msg_size, sizeof(*pkt)); + stm_size = stm_log_inv_ts(0, 0, pkt->rg_msg_data, pkt->msg_size); if (stm_size == 0) dprintk(VIDC_ERR, "In %s, stm_log returned size of 0\n", __func__); - } else { + + } else if (pkt->packet_type == HFI_MSG_SYS_DEBUG) { struct hfi_msg_sys_debug_packet *pkt = (struct hfi_msg_sys_debug_packet *) packet; + + SKIP_INVALID_PKT(pkt->size, + pkt->msg_size, sizeof(*pkt)); + /* * All fw messages starts with new line character. This * causes dprintk to print this message in two lines @@ -3487,9 +3516,11 @@ static void __flush_debug_queue(struct venus_hfi_device *device, u8 *packet) * from the message fixes this to print it in a single * line. */ + pkt->rg_msg_data[pkt->msg_size-1] = '\0'; dprintk(log_level, "%s", &pkt->rg_msg_data[1]); } } +#undef SKIP_INVALID_PKT if (local_packet) kfree(packet); diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h index 3e8d8b4e1d99..7853ed1b9518 100644 --- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h +++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2019, 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 @@ -905,6 +905,11 @@ struct vidc_hal_session_cmd_pkt { u32 session_id; }; +struct hfi_packet_header { + u32 size; + u32 packet_type; +}; + struct hfi_cmd_sys_init_packet { u32 size; u32 packet_type; diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index f5b17e5e0b93..77a2c0cb612e 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -1054,11 +1054,19 @@ static int uvc_parse_standard_control(struct uvc_device *dev, return -EINVAL; } - /* Make sure the terminal type MSB is not null, otherwise it - * could be confused with a unit. + /* + * Reject invalid terminal types that would cause issues: + * + * - The high byte must be non-zero, otherwise it would be + * confused with a unit. + * + * - Bit 15 must be 0, as we use it internally as a terminal + * direction flag. + * + * Other unknown types are accepted. */ type = get_unaligned_le16(&buffer[4]); - if ((type & 0xff00) == 0) { + if ((type & 0x7f00) == 0 || (type & 0x8000) != 0) { uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol " "interface %d INPUT_TERMINAL %d has invalid " "type 0x%04x, skipping\n", udev->devnum, diff --git a/drivers/nfc/nq-nci.c b/drivers/nfc/nq-nci.c index 4f46155cf22a..19829a9a8623 100644 --- a/drivers/nfc/nq-nci.c +++ b/drivers/nfc/nq-nci.c @@ -841,6 +841,9 @@ static int nfcc_hw_check(struct i2c_client *client, struct nqx_dev *nqx_dev) reset_enable_gpio: /* making sure that the NFCC starts in a clean state. */ + gpio_set_value(enable_gpio, 1);/* HPD : Enable*/ + /* hardware dependent delay */ + usleep_range(10000, 10100); gpio_set_value(enable_gpio, 0);/* ULPM: Disable */ /* hardware dependent delay */ usleep_range(10000, 10100); @@ -906,8 +909,12 @@ reset_enable_gpio: } goto err_nfcc_reset_failed; } - /* hardware dependent delay */ - msleep(30); + nqx_enable_irq(nqx_dev); + ret = wait_event_interruptible(nqx_dev->read_wq, !nqx_dev->irq_enabled); + if (ret < 0) { + nqx_disable_irq(nqx_dev); + goto err_nfcc_hw_check; + } /* Read Response of RESET command */ ret = i2c_master_recv(client, nci_reset_rsp, NCI_RESET_RSP_LEN); @@ -919,9 +926,12 @@ reset_enable_gpio: goto reset_enable_gpio; goto err_nfcc_hw_check; } - - /* hardware dependent delay */ - msleep(30); + nqx_enable_irq(nqx_dev); + ret = wait_event_interruptible(nqx_dev->read_wq, !nqx_dev->irq_enabled); + if (ret < 0) { + nqx_disable_irq(nqx_dev); + goto err_nfcc_hw_check; + } /* Read Notification of RESET command */ ret = i2c_master_recv(client, nci_reset_ntf, NCI_RESET_NTF_LEN); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c index 53015f297612..d65f6518fdb7 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c @@ -1635,8 +1635,8 @@ int ipa3_tx_dp(enum ipa_client_type dst, struct sk_buff *skb, sys = ipa3_ctx->ep[src_ep_idx].sys; if (!sys || !sys->ep->valid) { - IPAERR_RL("pipe not valid\n"); - goto fail_gen; + IPAERR_RL("pipe %d not valid\n", src_ep_idx); + goto fail_pipe_not_valid; } num_frags = skb_shinfo(skb)->nr_frags; @@ -1799,6 +1799,8 @@ fail_mem: kfree(desc); fail_gen: return -EFAULT; +fail_pipe_not_valid: + return -EPIPE; } static void ipa3_wq_handle_rx(struct work_struct *work) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi_proxy.c b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi_proxy.c index 3fef83623790..d7f721f9d258 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi_proxy.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi_proxy.c @@ -648,7 +648,7 @@ struct ipa_mhi_clk_vote_resp_msg_v01 * executed from mhi context. */ if (vote) { - ret = mhi_device_get_sync(imp_ctx->md.mhi_dev); + ret = mhi_device_get_sync(imp_ctx->md.mhi_dev, 0); if (ret) { IMP_ERR("mhi_sync_get failed %d\n", ret); resp->resp.result = IPA_QMI_RESULT_FAILURE_V01; @@ -658,7 +658,7 @@ struct ipa_mhi_clk_vote_resp_msg_v01 return resp; } } else { - mhi_device_put(imp_ctx->md.mhi_dev); + mhi_device_put(imp_ctx->md.mhi_dev, 0); } mutex_lock(&imp_ctx->mutex); @@ -719,7 +719,7 @@ static void imp_mhi_shutdown(void) false); } if (imp_ctx->lpm_disabled) { - mhi_device_put(imp_ctx->md.mhi_dev); + mhi_device_put(imp_ctx->md.mhi_dev, 0); imp_ctx->lpm_disabled = false; } diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c index 208bf2f0cea7..0f700a41fc49 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c @@ -1178,7 +1178,7 @@ send: dev_kfree_skb_any(skb); dev->stats.tx_dropped++; spin_unlock_irqrestore(&wwan_ptr->lock, flags); - return -EFAULT; + return NETDEV_TX_OK; } /* IPA_RM checking end */ @@ -1188,6 +1188,14 @@ send: */ ret = ipa3_tx_dp(IPA_CLIENT_APPS_WAN_PROD, skb, NULL); if (ret) { + if (ret == -EPIPE) { + IPAWANERR_RL("[%s] fatal: pipe is not valid\n", + dev->name); + dev_kfree_skb_any(skb); + dev->stats.tx_dropped++; + spin_unlock_irqrestore(&wwan_ptr->lock, flags); + return NETDEV_TX_OK; + } ret = NETDEV_TX_BUSY; goto out; } @@ -2649,6 +2657,7 @@ static int ipa3_wwan_remove(struct platform_device *pdev) if (ipa3_rmnet_res.ipa_napi_enable) netif_napi_del(&(rmnet_ipa3_ctx->wwan_priv->napi)); mutex_unlock(&rmnet_ipa3_ctx->pipe_handle_guard); + IPAWANINFO("rmnet_ipa unregister_netdev\n"); unregister_netdev(IPA_NETDEV()); if (ipa3_ctx->use_ipa_pm) ipa3_wwan_deregister_netdev_pm_client(); diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index 5e3b621a0ec3..58d68d2d3f11 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -5141,6 +5141,8 @@ enum alarmtimer_restart smblib_lpd_recheck_timer(struct alarm *alarm, pval.intval, rc); return ALARMTIMER_NORESTART; } + chg->moisture_present = false; + power_supply_changed(chg->usb_psy); } else { rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG, TYPEC_WATER_DETECTION_INT_EN_BIT, @@ -5196,8 +5198,10 @@ static bool smblib_src_lpd(struct smb_charger *chg) smblib_err(chg, "Couldn't write 0x%02x to TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n", pval.intval, rc); chg->lpd_reason = LPD_MOISTURE_DETECTED; + chg->moisture_present = true; alarm_start_relative(&chg->lpd_recheck_timer, ms_to_ktime(60000)); + power_supply_changed(chg->usb_psy); } else { chg->lpd_reason = LPD_NONE; chg->typec_mode = smblib_get_prop_typec_mode(chg); @@ -6507,6 +6511,7 @@ static void smblib_lpd_ra_open_work(struct work_struct *work) } chg->lpd_reason = LPD_MOISTURE_DETECTED; + chg->moisture_present = true; } else { /* Floating cable, disable water detection irq temporarily */ diff --git a/drivers/soc/qcom/qmi_interface.c b/drivers/soc/qcom/qmi_interface.c index 381f224ac5ca..bc1766186389 100644 --- a/drivers/soc/qcom/qmi_interface.c +++ b/drivers/soc/qcom/qmi_interface.c @@ -317,7 +317,6 @@ int qmi_txn_init(struct qmi_handle *qmi, struct qmi_txn *txn, memset(txn, 0, sizeof(*txn)); - mutex_init(&txn->lock); init_completion(&txn->completion); txn->qmi = qmi; txn->ei = ei; @@ -353,17 +352,12 @@ int qmi_txn_wait(struct qmi_txn *txn, unsigned long timeout) ret = wait_for_completion_timeout(&txn->completion, timeout); - mutex_lock(&txn->lock); if (txn->result == -ENETRESET) { - mutex_unlock(&txn->lock); return txn->result; } - mutex_unlock(&txn->lock); mutex_lock(&qmi->txn_lock); - mutex_lock(&txn->lock); idr_remove(&qmi->txns, txn->id); - mutex_unlock(&txn->lock); mutex_unlock(&qmi->txn_lock); if (ret == 0) @@ -382,9 +376,7 @@ void qmi_txn_cancel(struct qmi_txn *txn) struct qmi_handle *qmi = txn->qmi; mutex_lock(&qmi->txn_lock); - mutex_lock(&txn->lock); idr_remove(&qmi->txns, txn->id); - mutex_unlock(&txn->lock); mutex_unlock(&qmi->txn_lock); } EXPORT_SYMBOL(qmi_txn_cancel); @@ -507,24 +499,22 @@ static void qmi_handle_message(struct qmi_handle *qmi, if (hdr->type == QMI_RESPONSE) { mutex_lock(&qmi->txn_lock); txn = idr_find(&qmi->txns, hdr->txn_id); - if (txn) - mutex_lock(&txn->lock); - mutex_unlock(&qmi->txn_lock); - } - - if (txn && txn->dest && txn->ei) { - ret = qmi_decode_message(buf, len, txn->ei, txn->dest); - if (ret < 0) - pr_err("failed to decode incoming message\n"); - - txn->result = ret; - complete(&txn->completion); - - mutex_unlock(&txn->lock); - } else if (txn) { - qmi_invoke_handler(qmi, sq, txn, buf, len); + /* Ignore unexpected responses */ + if (!txn) { + mutex_unlock(&qmi->txn_lock); + return; + } + if (txn->dest && txn->ei) { + ret = qmi_decode_message(buf, len, txn->ei, txn->dest); + if (ret < 0) + pr_err("failed to decode incoming message\n"); - mutex_unlock(&txn->lock); + txn->result = ret; + complete(&txn->completion); + } else { + qmi_invoke_handler(qmi, sq, txn, buf, len); + } + mutex_unlock(&qmi->txn_lock); } else { /* Create a txn based on the txn_id of the incoming message */ memset(&tmp_txn, 0, sizeof(tmp_txn)); @@ -735,11 +725,9 @@ void qmi_handle_release(struct qmi_handle *qmi) mutex_lock(&qmi->txn_lock); idr_for_each_entry(&qmi->txns, txn, txn_id) { - mutex_lock(&txn->lock); idr_remove(&qmi->txns, txn->id); txn->result = -ENETRESET; complete(&txn->completion); - mutex_unlock(&txn->lock); } mutex_unlock(&qmi->txn_lock); idr_destroy(&qmi->txns); diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index ff5a833df816..9463abd99b50 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2019, 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 @@ -1009,6 +1009,10 @@ static void gsi_store_ringbase_dbl_info(struct usb_ep *ep, * Replace dummy doorbell address with real one as IPA connection * is setup now and GSI must be ready to handle doorbell updates. */ + dwc3_msm_write_reg_field(mdwc->base, + GSI_DBL_ADDR_H(mdwc->gsi_reg[DBL_ADDR_H], (n)), + ~0x0, 0x0); + dwc3_msm_write_reg(mdwc->base, GSI_DBL_ADDR_L(mdwc->gsi_reg[DBL_ADDR_L], (n)), (u32)request->mapped_db_reg_phs_addr_lsb); @@ -1287,6 +1291,10 @@ static void gsi_configure_ep(struct usb_ep *ep, struct usb_gsi_request *request) /* setup dummy doorbell as IPA connection isn't setup yet */ dwc3_msm_write_reg_field(mdwc->base, + GSI_DBL_ADDR_H(mdwc->gsi_reg[DBL_ADDR_H], (n)), + ~0x0, (u32)((u64)mdwc->dummy_gsi_db_dma >> 32)); + + dwc3_msm_write_reg_field(mdwc->base, GSI_DBL_ADDR_L(mdwc->gsi_reg[DBL_ADDR_L], (n)), ~0x0, (u32)mdwc->dummy_gsi_db_dma); dev_dbg(mdwc->dev, "Dummy DB Addr %pK: %llx %llx (LSB)\n", diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 08d6c94e117e..97626cacfe5c 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -329,6 +329,7 @@ static ssize_t gadget_dev_desc_UDC_store(struct config_item *item, gi->composite.gadget_driver.udc_name = NULL; goto err; } + schedule_work(&gi->work); } mutex_unlock(&gi->lock); return len; diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index 3b9aaafb758e..3063105e18c7 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -524,7 +524,7 @@ static int ipa_connect_channels(struct gsi_data_port *d_port) if (ret) { log_event_err("%s: GSI_EP_OP_STARTXFER failed: %d\n", __func__, ret); - return ret; + goto free_trb_ep_in; } d_port->in_xfer_rsc_index = usb_gsi_ep_op(d_port->in_ep, NULL, @@ -572,7 +572,7 @@ static int ipa_connect_channels(struct gsi_data_port *d_port) if (ret) { log_event_err("%s: GSI_EP_OP_PREPARE_TRBS failed: %d\n", __func__, ret); - return ret; + goto end_xfer_ep_in; } ret = usb_gsi_ep_op(d_port->out_ep, &d_port->out_request, @@ -580,7 +580,7 @@ static int ipa_connect_channels(struct gsi_data_port *d_port) if (ret) { log_event_err("%s: GSI_EP_OP_STARTXFER failed: %d\n", __func__, ret); - return ret; + goto free_trb_ep_out; } d_port->out_xfer_rsc_index = @@ -664,7 +664,7 @@ static int ipa_connect_channels(struct gsi_data_port *d_port) conn_params); if (ret) { log_event_err("%s: IPA connect failed %d", __func__, ret); - return ret; + goto end_xfer_ep_out; } log_event_dbg("%s: xdci_connect done", __func__); @@ -692,6 +692,21 @@ static int ipa_connect_channels(struct gsi_data_port *d_port) d_port->out_request.db_reg_phs_addr_msb = ipa_out_channel_out_params.db_reg_phs_addr_msb; } + + return ret; + +end_xfer_ep_out: + usb_gsi_ep_op(d_port->out_ep, NULL, + GSI_EP_OP_ENDXFER); +free_trb_ep_out: + usb_gsi_ep_op(d_port->out_ep, &d_port->out_request, + GSI_EP_OP_FREE_TRBS); +end_xfer_ep_in: + usb_gsi_ep_op(d_port->in_ep, NULL, + GSI_EP_OP_ENDXFER); +free_trb_ep_in: + usb_gsi_ep_op(d_port->in_ep, &d_port->in_request, + GSI_EP_OP_FREE_TRBS); return ret; } @@ -893,14 +908,26 @@ static void ipa_work_handler(struct work_struct *w) if (ret) { log_event_err("%s: gsi_alloc_trb_failed\n", __func__); + usb_gadget_autopm_put_async(d_port->gadget); break; } d_port->sm_state = STATE_CONNECT_IN_PROGRESS; log_event_dbg("%s: ST_INIT_EVT_CONN_IN_PROG", __func__); - if (peek_event(d_port) != EVT_DISCONNECTED) - ipa_connect_channels(d_port); + if (peek_event(d_port) != EVT_DISCONNECTED) { + ret = ipa_connect_channels(d_port); + if (ret) { + log_event_err("%s: ipa_connect_channels failed\n", + __func__); + gsi_free_trb_buffer(gsi); + usb_gadget_autopm_put_async( + d_port->gadget); + d_port->sm_state = STATE_INITIALIZED; + break; + } + } + } else if (event == EVT_HOST_READY) { /* * When in a composition such as RNDIS + ADB, @@ -920,10 +947,19 @@ static void ipa_work_handler(struct work_struct *w) if (ret) { log_event_err("%s: gsi_alloc_trb_failed\n", __func__); + usb_gadget_autopm_put_async(d_port->gadget); + break; + } + + ret = ipa_connect_channels(d_port); + if (ret) { + log_event_err("%s: ipa_connect_channels failed\n", + __func__); + gsi_free_trb_buffer(gsi); + usb_gadget_autopm_put_async(d_port->gadget); break; } - ipa_connect_channels(d_port); ipa_data_path_enable(d_port); d_port->sm_state = STATE_CONNECTED; log_event_dbg("%s: ST_INIT_EVT_HOST_READY", __func__); @@ -1034,16 +1070,6 @@ static void ipa_work_handler(struct work_struct *w) log_event_dbg("%s: ST_CON_EVT_CON", __func__); } break; - case STATE_DISCONNECTED: - if (event == EVT_CONNECT_IN_PROGRESS) { - ipa_connect_channels(d_port); - d_port->sm_state = STATE_CONNECT_IN_PROGRESS; - log_event_dbg("%s: ST_DIS_EVT_CON_IN_PROG", __func__); - } else if (event == EVT_UNINITIALIZED) { - d_port->sm_state = STATE_UNINITIALIZED; - log_event_dbg("%s: ST_DIS_EVT_UNINIT", __func__); - } - break; case STATE_SUSPEND_IN_PROGRESS: if (event == EVT_IPA_SUSPEND) { d_port->sm_state = STATE_SUSPENDED; diff --git a/include/linux/mhi.h b/include/linux/mhi.h index d1f2bca394b0..0b68b704fd4e 100644 --- a/include/linux/mhi.h +++ b/include/linux/mhi.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2019, 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 @@ -114,6 +114,9 @@ enum mhi_dev_state { MHI_STATE_MAX, }; +#define MHI_VOTE_BUS BIT(0) /* do not disable the bus */ +#define MHI_VOTE_DEVICE BIT(1) /* prevent mhi device from entering lpm */ + /** * struct image_info - firmware and rddm table table * @mhi_buf - Contain device firmware and rddm table @@ -301,6 +304,8 @@ struct mhi_controller { * @ul_chan_id: MHI channel id for UL transfer * @dl_chan_id: MHI channel id for DL transfer * @tiocm: Device current terminal settings + * @early_notif: This device needs an early notification in case of error + * with external modem. * @priv: Driver private data */ struct mhi_device { @@ -315,6 +320,7 @@ struct mhi_device { int ul_event_id; int dl_event_id; u32 tiocm; + bool early_notif; const struct mhi_device_id *id; const char *chan_name; struct mhi_controller *mhi_cntrl; @@ -458,22 +464,25 @@ int mhi_device_configure(struct mhi_device *mhi_div, * Only disables lpm, does not immediately exit low power mode * if controller already in a low power mode * @mhi_dev: Device associated with the channels + * @vote: requested vote (for future usage) */ -void mhi_device_get(struct mhi_device *mhi_dev); +void mhi_device_get(struct mhi_device *mhi_dev, int vote); /** * mhi_device_get_sync - disable all low power modes * Synchronously disable all low power, exit low power mode if * controller already in a low power state * @mhi_dev: Device associated with the channels + * @vote: requested vote (for future usage) */ -int mhi_device_get_sync(struct mhi_device *mhi_dev); +int mhi_device_get_sync(struct mhi_device *mhi_dev, int vote); /** * mhi_device_put - re-enable low power modes * @mhi_dev: Device associated with the channels + * @vote: requested vote (for future usage) */ -void mhi_device_put(struct mhi_device *mhi_dev); +void mhi_device_put(struct mhi_device *mhi_dev, int vote); /** * mhi_prepare_for_transfer - setup channel for data transfer @@ -642,6 +651,15 @@ static inline bool mhi_is_active(struct mhi_device *mhi_dev) mhi_cntrl->dev_state <= MHI_STATE_M3); } + +/** + * mhi_control_error - MHI controller went into unrecoverable error state. + * Will transition MHI into Linkdown state. Do not call from atomic + * context. + * @mhi_cntrl: MHI controller + */ +void mhi_control_error(struct mhi_controller *mhi_cntrl); + #ifndef CONFIG_ARCH_QCOM #ifdef CONFIG_MHI_DEBUG diff --git a/include/linux/soc/qcom/qmi.h b/include/linux/soc/qcom/qmi.h index 8a0fa18fa14f..e18648be7747 100644 --- a/include/linux/soc/qcom/qmi.h +++ b/include/linux/soc/qcom/qmi.h @@ -166,7 +166,6 @@ struct qmi_ops { * struct qmi_txn - transaction context * @qmi: QMI handle this transaction is associated with * @id: transaction id - * @lock: for synchronization between handler and waiter of messages * @completion: completion object as the transaction receives a response * @result: result code for the completed transaction * @ei: description of the QMI encoded response (optional) @@ -177,7 +176,6 @@ struct qmi_txn { u16 id; - struct mutex lock; struct completion completion; int result; diff --git a/include/uapi/media/cam_isp.h b/include/uapi/media/cam_isp.h index de32a61b539c..68e8446f1585 100644 --- a/include/uapi/media/cam_isp.h +++ b/include/uapi/media/cam_isp.h @@ -91,6 +91,7 @@ #define CAM_ISP_GENERIC_BLOB_TYPE_CSID_CLOCK_CONFIG 4 #define CAM_ISP_GENERIC_BLOB_TYPE_FE_CONFIG 5 #define CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG_V2 6 +#define CAM_ISP_GENERIC_BLOB_TYPE_INIT_FRAME_DROP 10 /* Per Path Usage Data */ #define CAM_ISP_USAGE_INVALID 0 @@ -500,4 +501,14 @@ struct cam_isp_acquire_hw_info { #define CAM_ISP_ACQUIRE_OUT_SIZE_VER0 sizeof(struct cam_isp_out_port_info) +/** + * struct cam_isp_init_frame_drop_config - init frame drop configuration + * + * @init_frame_drop: Initial number of frames needs to drop + */ + +struct cam_isp_init_frame_drop_config { + uint32_t init_frame_drop; +} __attribute__((packed)); + #endif /* __UAPI_CAM_ISP_H__ */ diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h index b903078dccbd..9b9f97bd50d5 100644 --- a/include/uapi/media/cam_req_mgr.h +++ b/include/uapi/media/cam_req_mgr.h @@ -35,6 +35,7 @@ * It includes both session and device handles */ #define CAM_REQ_MGR_MAX_HANDLES 64 +#define CAM_REQ_MGR_MAX_HANDLES_V2 128 #define MAX_LINKS_PER_SESSION 2 /* V4L event type which user space will subscribe to */ @@ -121,6 +122,20 @@ struct cam_req_mgr_link_info { int32_t link_hdl; }; +struct cam_req_mgr_link_info_v2 { + int32_t session_hdl; + uint32_t num_devices; + int32_t dev_hdls[CAM_REQ_MGR_MAX_HANDLES_V2]; + int32_t link_hdl; +}; + +struct cam_req_mgr_ver_info { + uint32_t version; + union { + struct cam_req_mgr_link_info link_info_v1; + struct cam_req_mgr_link_info_v2 link_info_v2; + } u; +}; /** * struct cam_req_mgr_unlink_info * @session_hdl: input param - session handle @@ -230,6 +245,7 @@ struct cam_req_mgr_link_control { #define CAM_REQ_MGR_RELEASE_BUF (CAM_COMMON_OPCODE_MAX + 11) #define CAM_REQ_MGR_CACHE_OPS (CAM_COMMON_OPCODE_MAX + 12) #define CAM_REQ_MGR_LINK_CONTROL (CAM_COMMON_OPCODE_MAX + 13) +#define CAM_REQ_MGR_LINK_V2 (CAM_COMMON_OPCODE_MAX + 14) /* end of cam_req_mgr opcodes */ #define CAM_MEM_FLAG_HW_READ_WRITE (1<<0) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 1e6b97edc4fa..6083235cce62 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -13000,13 +13000,13 @@ void check_for_migration(struct rq *rq, struct task_struct *p) rcu_read_lock(); new_cpu = find_energy_efficient_cpu(sd, p, cpu, prev_cpu, 0); rcu_read_unlock(); - if ((new_cpu != -1) && - (capacity_orig_of(new_cpu) > capacity_orig_of(cpu))) { + if ((new_cpu != prev_cpu) && (capacity_orig_of(new_cpu) > + capacity_orig_of(prev_cpu))) { active_balance = kick_active_balance(rq, p, new_cpu); if (active_balance) { mark_reserved(new_cpu); raw_spin_unlock(&migration_lock); - stop_one_cpu_nowait(cpu, + stop_one_cpu_nowait(prev_cpu, active_load_balance_cpu_stop, rq, &rq->active_balance_work); return; diff --git a/net/qrtr/mhi.c b/net/qrtr/mhi.c index dbc0d1efaadf..90dc2e917f5b 100644 --- a/net/qrtr/mhi.c +++ b/net/qrtr/mhi.c @@ -25,6 +25,7 @@ struct qrtr_mhi_dev { struct device *dev; spinlock_t ul_lock; /* lock to protect ul_pkts */ struct list_head ul_pkts; + atomic_t in_reset; }; struct qrtr_mhi_pkt { @@ -68,14 +69,33 @@ static void qcom_mhi_qrtr_ul_callback(struct mhi_device *mhi_dev, { struct qrtr_mhi_dev *qdev = dev_get_drvdata(&mhi_dev->dev); struct qrtr_mhi_pkt *pkt; + unsigned long flags; - spin_lock_bh(&qdev->ul_lock); + spin_lock_irqsave(&qdev->ul_lock, flags); pkt = list_first_entry(&qdev->ul_pkts, struct qrtr_mhi_pkt, node); list_del(&pkt->node); complete_all(&pkt->done); kref_put(&pkt->refcount, qrtr_mhi_pkt_release); - spin_unlock_bh(&qdev->ul_lock); + spin_unlock_irqrestore(&qdev->ul_lock, flags); +} + +/* fatal error */ +static void qcom_mhi_qrtr_status_callback(struct mhi_device *mhi_dev, + enum MHI_CB mhi_cb) +{ + struct qrtr_mhi_dev *qdev = dev_get_drvdata(&mhi_dev->dev); + struct qrtr_mhi_pkt *pkt; + unsigned long flags; + + if (mhi_cb != MHI_CB_FATAL_ERROR) + return; + + atomic_inc(&qdev->in_reset); + spin_lock_irqsave(&qdev->ul_lock, flags); + list_for_each_entry(pkt, &qdev->ul_pkts, node) + complete_all(&pkt->done); + spin_unlock_irqrestore(&qdev->ul_lock, flags); } /* from qrtr to mhi */ @@ -118,10 +138,12 @@ static int qcom_mhi_qrtr_send(struct qrtr_endpoint *ep, struct sk_buff *skb) sock_hold(skb->sk); rc = wait_for_completion_interruptible_timeout(&pkt->done, HZ * 5); - if (rc > 0) - rc = 0; + if (atomic_read(&qdev->in_reset)) + rc = -ECONNRESET; else if (rc == 0) rc = -ETIMEDOUT; + else if (rc > 0) + rc = 0; kref_put(&pkt->refcount, qrtr_mhi_pkt_release); return rc; @@ -142,6 +164,7 @@ static int qcom_mhi_qrtr_probe(struct mhi_device *mhi_dev, qdev->mhi_dev = mhi_dev; qdev->dev = &mhi_dev->dev; qdev->ep.xmit = qcom_mhi_qrtr_send; + atomic_set(&qdev->in_reset, 0); rc = of_property_read_u32(mhi_dev->dev.of_node, "qcom,net-id", &net_id); if (rc < 0) @@ -181,6 +204,7 @@ static struct mhi_driver qcom_mhi_qrtr_driver = { .remove = qcom_mhi_qrtr_remove, .dl_xfer_cb = qcom_mhi_qrtr_dl_callback, .ul_xfer_cb = qcom_mhi_qrtr_ul_callback, + .status_cb = qcom_mhi_qrtr_status_callback, .id_table = qcom_mhi_qrtr_mhi_match, .driver = { .name = "qcom_mhi_qrtr", |