diff options
author | 2022-09-08 06:48:13 -0400 | |
---|---|---|
committer | 2022-09-08 06:48:13 -0400 | |
commit | 490d5af622c424f52dc4032477639b11b50edfa8 (patch) | |
tree | a8971b919d4ac3b231e43025a53652ba5fedc748 | |
parent | Linux patch 5.15.65 (diff) | |
download | linux-patches-490d5af622c424f52dc4032477639b11b50edfa8.tar.gz linux-patches-490d5af622c424f52dc4032477639b11b50edfa8.tar.bz2 linux-patches-490d5af622c424f52dc4032477639b11b50edfa8.zip |
Linux patch 5.15.665.15-70
Signed-off-by: Mike Pagano <mpagano@gentoo.org>
-rw-r--r-- | 0000_README | 4 | ||||
-rw-r--r-- | 1065_linux-5.15.66.patch | 7081 |
2 files changed, 7085 insertions, 0 deletions
diff --git a/0000_README b/0000_README index 079ad2a6..25df4d69 100644 --- a/0000_README +++ b/0000_README @@ -303,6 +303,10 @@ Patch: 1064_linux-5.15.65.patch From: http://www.kernel.org Desc: Linux 5.15.65 +Patch: 1065_linux-5.15.66.patch +From: http://www.kernel.org +Desc: Linux 5.15.66 + Patch: 1500_XATTR_USER_PREFIX.patch From: https://bugs.gentoo.org/show_bug.cgi?id=470644 Desc: Support for namespace user.pax.* on tmpfs. diff --git a/1065_linux-5.15.66.patch b/1065_linux-5.15.66.patch new file mode 100644 index 00000000..731e8732 --- /dev/null +++ b/1065_linux-5.15.66.patch @@ -0,0 +1,7081 @@ +diff --git a/Makefile b/Makefile +index 9142dbf41f0d8..4e747c99e7e07 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,7 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 + VERSION = 5 + PATCHLEVEL = 15 +-SUBLEVEL = 65 ++SUBLEVEL = 66 + EXTRAVERSION = + NAME = Trick or Treat + +@@ -480,6 +480,8 @@ LZ4 = lz4c + XZ = xz + ZSTD = zstd + ++PAHOLE_FLAGS = $(shell PAHOLE=$(PAHOLE) $(srctree)/scripts/pahole-flags.sh) ++ + CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \ + -Wbitwise -Wno-return-void -Wno-unknown-attribute $(CF) + NOSTDINC_FLAGS := +@@ -534,6 +536,7 @@ export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE + export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE + export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE + export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL ++export PAHOLE_FLAGS + + # Files to ignore in find ... statements + +diff --git a/arch/powerpc/kernel/systbl.S b/arch/powerpc/kernel/systbl.S +index cb3358886203e..6c1db3b6de2dc 100644 +--- a/arch/powerpc/kernel/systbl.S ++++ b/arch/powerpc/kernel/systbl.S +@@ -18,6 +18,7 @@ + .p2align 3 + #define __SYSCALL(nr, entry) .8byte entry + #else ++ .p2align 2 + #define __SYSCALL(nr, entry) .long entry + #endif + +diff --git a/arch/riscv/mm/pageattr.c b/arch/riscv/mm/pageattr.c +index 5e49e4b4a4ccc..86c56616e5dea 100644 +--- a/arch/riscv/mm/pageattr.c ++++ b/arch/riscv/mm/pageattr.c +@@ -118,10 +118,10 @@ static int __set_memory(unsigned long addr, int numpages, pgprot_t set_mask, + if (!numpages) + return 0; + +- mmap_read_lock(&init_mm); ++ mmap_write_lock(&init_mm); + ret = walk_page_range_novma(&init_mm, start, end, &pageattr_ops, NULL, + &masks); +- mmap_read_unlock(&init_mm); ++ mmap_write_unlock(&init_mm); + + flush_tlb_kernel_range(start, end); + +diff --git a/arch/s390/include/asm/hugetlb.h b/arch/s390/include/asm/hugetlb.h +index 60f9241e5e4a6..d3642fb634bd9 100644 +--- a/arch/s390/include/asm/hugetlb.h ++++ b/arch/s390/include/asm/hugetlb.h +@@ -28,9 +28,11 @@ pte_t huge_ptep_get_and_clear(struct mm_struct *mm, + static inline int prepare_hugepage_range(struct file *file, + unsigned long addr, unsigned long len) + { +- if (len & ~HPAGE_MASK) ++ struct hstate *h = hstate_file(file); ++ ++ if (len & ~huge_page_mask(h)) + return -EINVAL; +- if (addr & ~HPAGE_MASK) ++ if (addr & ~huge_page_mask(h)) + return -EINVAL; + return 0; + } +diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S +index 42c43521878ff..b508ccad4856d 100644 +--- a/arch/s390/kernel/vmlinux.lds.S ++++ b/arch/s390/kernel/vmlinux.lds.S +@@ -132,6 +132,7 @@ SECTIONS + /* + * Table with the patch locations to undo expolines + */ ++ . = ALIGN(4); + .nospec_call_table : { + __nospec_call_start = . ; + *(.s390_indirect*) +diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c +index cfb3a5c809f2e..e5584e974c774 100644 +--- a/arch/x86/kvm/vmx/vmx.c ++++ b/arch/x86/kvm/vmx/vmx.c +@@ -831,8 +831,7 @@ static bool msr_write_intercepted(struct vcpu_vmx *vmx, u32 msr) + if (!(exec_controls_get(vmx) & CPU_BASED_USE_MSR_BITMAPS)) + return true; + +- return vmx_test_msr_bitmap_write(vmx->loaded_vmcs->msr_bitmap, +- MSR_IA32_SPEC_CTRL); ++ return vmx_test_msr_bitmap_write(vmx->loaded_vmcs->msr_bitmap, msr); + } + + unsigned int __vmx_vcpu_run_flags(struct vcpu_vmx *vmx) +diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c +index f5b7a05530eb0..9109e5589b421 100644 +--- a/arch/x86/kvm/x86.c ++++ b/arch/x86/kvm/x86.c +@@ -1465,12 +1465,32 @@ static const u32 msr_based_features_all[] = { + static u32 msr_based_features[ARRAY_SIZE(msr_based_features_all)]; + static unsigned int num_msr_based_features; + ++/* ++ * Some IA32_ARCH_CAPABILITIES bits have dependencies on MSRs that KVM ++ * does not yet virtualize. These include: ++ * 10 - MISC_PACKAGE_CTRLS ++ * 11 - ENERGY_FILTERING_CTL ++ * 12 - DOITM ++ * 18 - FB_CLEAR_CTRL ++ * 21 - XAPIC_DISABLE_STATUS ++ * 23 - OVERCLOCKING_STATUS ++ */ ++ ++#define KVM_SUPPORTED_ARCH_CAP \ ++ (ARCH_CAP_RDCL_NO | ARCH_CAP_IBRS_ALL | ARCH_CAP_RSBA | \ ++ ARCH_CAP_SKIP_VMENTRY_L1DFLUSH | ARCH_CAP_SSB_NO | ARCH_CAP_MDS_NO | \ ++ ARCH_CAP_PSCHANGE_MC_NO | ARCH_CAP_TSX_CTRL_MSR | ARCH_CAP_TAA_NO | \ ++ ARCH_CAP_SBDR_SSDP_NO | ARCH_CAP_FBSDP_NO | ARCH_CAP_PSDP_NO | \ ++ ARCH_CAP_FB_CLEAR | ARCH_CAP_RRSBA | ARCH_CAP_PBRSB_NO) ++ + static u64 kvm_get_arch_capabilities(void) + { + u64 data = 0; + +- if (boot_cpu_has(X86_FEATURE_ARCH_CAPABILITIES)) ++ if (boot_cpu_has(X86_FEATURE_ARCH_CAPABILITIES)) { + rdmsrl(MSR_IA32_ARCH_CAPABILITIES, data); ++ data &= KVM_SUPPORTED_ARCH_CAP; ++ } + + /* + * If nx_huge_pages is enabled, KVM's shadow paging will ensure that +@@ -1518,9 +1538,6 @@ static u64 kvm_get_arch_capabilities(void) + */ + } + +- /* Guests don't need to know "Fill buffer clear control" exists */ +- data &= ~ARCH_CAP_FB_CLEAR_CTRL; +- + return data; + } + +diff --git a/drivers/android/binder.c b/drivers/android/binder.c +index 56a2387656a03..00c6c03ff8222 100644 +--- a/drivers/android/binder.c ++++ b/drivers/android/binder.c +@@ -1358,6 +1358,18 @@ static int binder_inc_ref_for_node(struct binder_proc *proc, + } + ret = binder_inc_ref_olocked(ref, strong, target_list); + *rdata = ref->data; ++ if (ret && ref == new_ref) { ++ /* ++ * Cleanup the failed reference here as the target ++ * could now be dead and have already released its ++ * references by now. Calling on the new reference ++ * with strong=0 and a tmp_refs will not decrement ++ * the node. The new_ref gets kfree'd below. ++ */ ++ binder_cleanup_ref_olocked(new_ref); ++ ref = NULL; ++ } ++ + binder_proc_unlock(proc); + if (new_ref && ref != new_ref) + /* +diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c +index f2d9587833d4b..849f8dff0be1b 100644 +--- a/drivers/android/binder_alloc.c ++++ b/drivers/android/binder_alloc.c +@@ -322,7 +322,6 @@ static inline void binder_alloc_set_vma(struct binder_alloc *alloc, + */ + if (vma) { + vm_start = vma->vm_start; +- alloc->vma_vm_mm = vma->vm_mm; + mmap_assert_write_locked(alloc->vma_vm_mm); + } else { + mmap_assert_locked(alloc->vma_vm_mm); +@@ -795,7 +794,6 @@ int binder_alloc_mmap_handler(struct binder_alloc *alloc, + binder_insert_free_buffer(alloc, buffer); + alloc->free_async_space = alloc->buffer_size / 2; + binder_alloc_set_vma(alloc, vma); +- mmgrab(alloc->vma_vm_mm); + + return 0; + +@@ -1095,6 +1093,8 @@ static struct shrinker binder_shrinker = { + void binder_alloc_init(struct binder_alloc *alloc) + { + alloc->pid = current->group_leader->pid; ++ alloc->vma_vm_mm = current->mm; ++ mmgrab(alloc->vma_vm_mm); + mutex_init(&alloc->mutex); + INIT_LIST_HEAD(&alloc->buffers); + } +diff --git a/drivers/base/dd.c b/drivers/base/dd.c +index 70e9ee8a10f79..63cc011188109 100644 +--- a/drivers/base/dd.c ++++ b/drivers/base/dd.c +@@ -877,6 +877,11 @@ static int __device_attach_driver(struct device_driver *drv, void *_data) + dev_dbg(dev, "Device match requests probe deferral\n"); + dev->can_match = true; + driver_deferred_probe_add(dev); ++ /* ++ * Device can't match with a driver right now, so don't attempt ++ * to match or bind with other drivers on the bus. ++ */ ++ return ret; + } else if (ret < 0) { + dev_dbg(dev, "Bus failed to match device: %d\n", ret); + return ret; +@@ -1115,6 +1120,11 @@ static int __driver_attach(struct device *dev, void *data) + dev_dbg(dev, "Device match requests probe deferral\n"); + dev->can_match = true; + driver_deferred_probe_add(dev); ++ /* ++ * Driver could not match with device, but may match with ++ * another device on the bus. ++ */ ++ return 0; + } else if (ret < 0) { + dev_dbg(dev, "Bus failed to match device: %d\n", ret); + return ret; +diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h +index bda5c815e4415..a28473470e662 100644 +--- a/drivers/block/xen-blkback/common.h ++++ b/drivers/block/xen-blkback/common.h +@@ -226,6 +226,9 @@ struct xen_vbd { + sector_t size; + unsigned int flush_support:1; + unsigned int discard_secure:1; ++ /* Connect-time cached feature_persistent parameter value */ ++ unsigned int feature_gnt_persistent_parm:1; ++ /* Persistent grants feature negotiation result */ + unsigned int feature_gnt_persistent:1; + unsigned int overflow_max_grants:1; + }; +diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c +index 78b50ac11e191..1525e28c5d703 100644 +--- a/drivers/block/xen-blkback/xenbus.c ++++ b/drivers/block/xen-blkback/xenbus.c +@@ -910,7 +910,7 @@ again: + xen_blkbk_barrier(xbt, be, be->blkif->vbd.flush_support); + + err = xenbus_printf(xbt, dev->nodename, "feature-persistent", "%u", +- be->blkif->vbd.feature_gnt_persistent); ++ be->blkif->vbd.feature_gnt_persistent_parm); + if (err) { + xenbus_dev_fatal(dev, err, "writing %s/feature-persistent", + dev->nodename); +@@ -1088,7 +1088,9 @@ static int connect_ring(struct backend_info *be) + return -ENOSYS; + } + +- blkif->vbd.feature_gnt_persistent = feature_persistent && ++ blkif->vbd.feature_gnt_persistent_parm = feature_persistent; ++ blkif->vbd.feature_gnt_persistent = ++ blkif->vbd.feature_gnt_persistent_parm && + xenbus_read_unsigned(dev->otherend, "feature-persistent", 0); + + blkif->vbd.overflow_max_grants = 0; +diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c +index 23fc4c8f26039..24a86d829f92a 100644 +--- a/drivers/block/xen-blkfront.c ++++ b/drivers/block/xen-blkfront.c +@@ -212,6 +212,9 @@ struct blkfront_info + unsigned int feature_fua:1; + unsigned int feature_discard:1; + unsigned int feature_secdiscard:1; ++ /* Connect-time cached feature_persistent parameter */ ++ unsigned int feature_persistent_parm:1; ++ /* Persistent grants feature negotiation result */ + unsigned int feature_persistent:1; + unsigned int bounce:1; + unsigned int discard_granularity; +@@ -1782,6 +1785,12 @@ abort_transaction: + return err; + } + ++/* Enable the persistent grants feature. */ ++static bool feature_persistent = true; ++module_param(feature_persistent, bool, 0644); ++MODULE_PARM_DESC(feature_persistent, ++ "Enables the persistent grants feature"); ++ + /* Common code used when first setting up, and when resuming. */ + static int talk_to_blkback(struct xenbus_device *dev, + struct blkfront_info *info) +@@ -1873,8 +1882,9 @@ again: + message = "writing protocol"; + goto abort_transaction; + } ++ info->feature_persistent_parm = feature_persistent; + err = xenbus_printf(xbt, dev->nodename, "feature-persistent", "%u", +- info->feature_persistent); ++ info->feature_persistent_parm); + if (err) + dev_warn(&dev->dev, + "writing persistent grants feature to xenbus"); +@@ -1942,12 +1952,6 @@ static int negotiate_mq(struct blkfront_info *info) + return 0; + } + +-/* Enable the persistent grants feature. */ +-static bool feature_persistent = true; +-module_param(feature_persistent, bool, 0644); +-MODULE_PARM_DESC(feature_persistent, +- "Enables the persistent grants feature"); +- + /* + * Entry point to this code when a new device is created. Allocate the basic + * structures and the ring buffer for communication with the backend, and +@@ -2307,7 +2311,7 @@ static void blkfront_gather_backend_features(struct blkfront_info *info) + if (xenbus_read_unsigned(info->xbdev->otherend, "feature-discard", 0)) + blkfront_setup_discard(info); + +- if (feature_persistent) ++ if (info->feature_persistent_parm) + info->feature_persistent = + !!xenbus_read_unsigned(info->xbdev->otherend, + "feature-persistent", 0); +diff --git a/drivers/clk/bcm/clk-raspberrypi.c b/drivers/clk/bcm/clk-raspberrypi.c +index dd3b71eafabf3..56c5166f841ae 100644 +--- a/drivers/clk/bcm/clk-raspberrypi.c ++++ b/drivers/clk/bcm/clk-raspberrypi.c +@@ -139,7 +139,7 @@ static unsigned long raspberrypi_fw_get_rate(struct clk_hw *hw, + ret = raspberrypi_clock_property(rpi->firmware, data, + RPI_FIRMWARE_GET_CLOCK_RATE, &val); + if (ret) +- return ret; ++ return 0; + + return val; + } +@@ -156,7 +156,7 @@ static int raspberrypi_fw_set_rate(struct clk_hw *hw, unsigned long rate, + ret = raspberrypi_clock_property(rpi->firmware, data, + RPI_FIRMWARE_SET_CLOCK_RATE, &_rate); + if (ret) +- dev_err_ratelimited(rpi->dev, "Failed to change %s frequency: %d", ++ dev_err_ratelimited(rpi->dev, "Failed to change %s frequency: %d\n", + clk_hw_get_name(hw), ret); + + return ret; +@@ -208,7 +208,7 @@ static struct clk_hw *raspberrypi_clk_register(struct raspberrypi_clk *rpi, + RPI_FIRMWARE_GET_MIN_CLOCK_RATE, + &min_rate); + if (ret) { +- dev_err(rpi->dev, "Failed to get clock %d min freq: %d", ++ dev_err(rpi->dev, "Failed to get clock %d min freq: %d\n", + id, ret); + return ERR_PTR(ret); + } +@@ -251,8 +251,13 @@ static int raspberrypi_discover_clocks(struct raspberrypi_clk *rpi, + struct rpi_firmware_get_clocks_response *clks; + int ret; + ++ /* ++ * The firmware doesn't guarantee that the last element of ++ * RPI_FIRMWARE_GET_CLOCKS is zeroed. So allocate an additional ++ * zero element as sentinel. ++ */ + clks = devm_kcalloc(rpi->dev, +- sizeof(*clks), RPI_FIRMWARE_NUM_CLK_ID, ++ RPI_FIRMWARE_NUM_CLK_ID + 1, sizeof(*clks), + GFP_KERNEL); + if (!clks) + return -ENOMEM; +diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c +index d6dc58bd07b33..0674dbc62eb55 100644 +--- a/drivers/clk/clk.c ++++ b/drivers/clk/clk.c +@@ -846,10 +846,9 @@ static void clk_core_unprepare(struct clk_core *core) + if (core->ops->unprepare) + core->ops->unprepare(core->hw); + +- clk_pm_runtime_put(core); +- + trace_clk_unprepare_complete(core); + clk_core_unprepare(core->parent); ++ clk_pm_runtime_put(core); + } + + static void clk_core_unprepare_lock(struct clk_core *core) +diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c +index 64befd6f702b2..4860bf3b7e002 100644 +--- a/drivers/gpio/gpio-pca953x.c ++++ b/drivers/gpio/gpio-pca953x.c +@@ -1163,7 +1163,9 @@ static int pca953x_suspend(struct device *dev) + { + struct pca953x_chip *chip = dev_get_drvdata(dev); + ++ mutex_lock(&chip->i2c_lock); + regcache_cache_only(chip->regmap, true); ++ mutex_unlock(&chip->i2c_lock); + + if (atomic_read(&chip->wakeup_path)) + device_set_wakeup_path(dev); +@@ -1186,13 +1188,17 @@ static int pca953x_resume(struct device *dev) + } + } + ++ mutex_lock(&chip->i2c_lock); + regcache_cache_only(chip->regmap, false); + regcache_mark_dirty(chip->regmap); + ret = pca953x_regcache_sync(dev); +- if (ret) ++ if (ret) { ++ mutex_unlock(&chip->i2c_lock); + return ret; ++ } + + ret = regcache_sync(chip->regmap); ++ mutex_unlock(&chip->i2c_lock); + if (ret) { + dev_err(dev, "Failed to restore register map: %d\n", ret); + return ret; +diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile +index 26cf754229451..9d371be7dc5cd 100644 +--- a/drivers/gpu/drm/i915/Makefile ++++ b/drivers/gpu/drm/i915/Makefile +@@ -249,6 +249,7 @@ i915-y += \ + display/g4x_dp.o \ + display/g4x_hdmi.o \ + display/icl_dsi.o \ ++ display/intel_backlight.o \ + display/intel_crt.o \ + display/intel_ddi.o \ + display/intel_ddi_buf_trans.o \ +diff --git a/drivers/gpu/drm/i915/display/g4x_dp.c b/drivers/gpu/drm/i915/display/g4x_dp.c +index de0f358184aa3..29c0eca647e34 100644 +--- a/drivers/gpu/drm/i915/display/g4x_dp.c ++++ b/drivers/gpu/drm/i915/display/g4x_dp.c +@@ -7,6 +7,7 @@ + + #include "g4x_dp.h" + #include "intel_audio.h" ++#include "intel_backlight.h" + #include "intel_connector.h" + #include "intel_de.h" + #include "intel_display_types.h" +@@ -16,7 +17,6 @@ + #include "intel_fifo_underrun.h" + #include "intel_hdmi.h" + #include "intel_hotplug.h" +-#include "intel_panel.h" + #include "intel_pps.h" + #include "intel_sideband.h" + +diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c +index 638a00b2dc2d2..2601873e15466 100644 +--- a/drivers/gpu/drm/i915/display/icl_dsi.c ++++ b/drivers/gpu/drm/i915/display/icl_dsi.c +@@ -29,6 +29,7 @@ + #include <drm/drm_mipi_dsi.h> + + #include "intel_atomic.h" ++#include "intel_backlight.h" + #include "intel_combo_phy.h" + #include "intel_connector.h" + #include "intel_crtc.h" +diff --git a/drivers/gpu/drm/i915/display/intel_backlight.c b/drivers/gpu/drm/i915/display/intel_backlight.c +new file mode 100644 +index 0000000000000..60f91ac7d1427 +--- /dev/null ++++ b/drivers/gpu/drm/i915/display/intel_backlight.c +@@ -0,0 +1,1776 @@ ++// SPDX-License-Identifier: MIT ++/* ++ * Copyright © 2021 Intel Corporation ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/pwm.h> ++ ++#include "intel_backlight.h" ++#include "intel_connector.h" ++#include "intel_de.h" ++#include "intel_display_types.h" ++#include "intel_dp_aux_backlight.h" ++#include "intel_dsi_dcs_backlight.h" ++#include "intel_panel.h" ++ ++/** ++ * scale - scale values from one range to another ++ * @source_val: value in range [@source_min..@source_max] ++ * @source_min: minimum legal value for @source_val ++ * @source_max: maximum legal value for @source_val ++ * @target_min: corresponding target value for @source_min ++ * @target_max: corresponding target value for @source_max ++ * ++ * Return @source_val in range [@source_min..@source_max] scaled to range ++ * [@target_min..@target_max]. ++ */ ++static u32 scale(u32 source_val, ++ u32 source_min, u32 source_max, ++ u32 target_min, u32 target_max) ++{ ++ u64 target_val; ++ ++ WARN_ON(source_min > source_max); ++ WARN_ON(target_min > target_max); ++ ++ /* defensive */ ++ source_val = clamp(source_val, source_min, source_max); ++ ++ /* avoid overflows */ ++ target_val = mul_u32_u32(source_val - source_min, ++ target_max - target_min); ++ target_val = DIV_ROUND_CLOSEST_ULL(target_val, source_max - source_min); ++ target_val += target_min; ++ ++ return target_val; ++} ++ ++/* ++ * Scale user_level in range [0..user_max] to [0..hw_max], clamping the result ++ * to [hw_min..hw_max]. ++ */ ++static u32 clamp_user_to_hw(struct intel_connector *connector, ++ u32 user_level, u32 user_max) ++{ ++ struct intel_panel *panel = &connector->panel; ++ u32 hw_level; ++ ++ hw_level = scale(user_level, 0, user_max, 0, panel->backlight.max); ++ hw_level = clamp(hw_level, panel->backlight.min, panel->backlight.max); ++ ++ return hw_level; ++} ++ ++/* Scale hw_level in range [hw_min..hw_max] to [0..user_max]. */ ++static u32 scale_hw_to_user(struct intel_connector *connector, ++ u32 hw_level, u32 user_max) ++{ ++ struct intel_panel *panel = &connector->panel; ++ ++ return scale(hw_level, panel->backlight.min, panel->backlight.max, ++ 0, user_max); ++} ++ ++u32 intel_panel_invert_pwm_level(struct intel_connector *connector, u32 val) ++{ ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ struct intel_panel *panel = &connector->panel; ++ ++ drm_WARN_ON(&dev_priv->drm, panel->backlight.pwm_level_max == 0); ++ ++ if (dev_priv->params.invert_brightness < 0) ++ return val; ++ ++ if (dev_priv->params.invert_brightness > 0 || ++ dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) { ++ return panel->backlight.pwm_level_max - val + panel->backlight.pwm_level_min; ++ } ++ ++ return val; ++} ++ ++void intel_panel_set_pwm_level(const struct drm_connector_state *conn_state, u32 val) ++{ ++ struct intel_connector *connector = to_intel_connector(conn_state->connector); ++ struct drm_i915_private *i915 = to_i915(connector->base.dev); ++ struct intel_panel *panel = &connector->panel; ++ ++ drm_dbg_kms(&i915->drm, "set backlight PWM = %d\n", val); ++ panel->backlight.pwm_funcs->set(conn_state, val); ++} ++ ++u32 intel_panel_backlight_level_to_pwm(struct intel_connector *connector, u32 val) ++{ ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ struct intel_panel *panel = &connector->panel; ++ ++ drm_WARN_ON_ONCE(&dev_priv->drm, ++ panel->backlight.max == 0 || panel->backlight.pwm_level_max == 0); ++ ++ val = scale(val, panel->backlight.min, panel->backlight.max, ++ panel->backlight.pwm_level_min, panel->backlight.pwm_level_max); ++ ++ return intel_panel_invert_pwm_level(connector, val); ++} ++ ++u32 intel_panel_backlight_level_from_pwm(struct intel_connector *connector, u32 val) ++{ ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ struct intel_panel *panel = &connector->panel; ++ ++ drm_WARN_ON_ONCE(&dev_priv->drm, ++ panel->backlight.max == 0 || panel->backlight.pwm_level_max == 0); ++ ++ if (dev_priv->params.invert_brightness > 0 || ++ (dev_priv->params.invert_brightness == 0 && dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS)) ++ val = panel->backlight.pwm_level_max - (val - panel->backlight.pwm_level_min); ++ ++ return scale(val, panel->backlight.pwm_level_min, panel->backlight.pwm_level_max, ++ panel->backlight.min, panel->backlight.max); ++} ++ ++static u32 lpt_get_backlight(struct intel_connector *connector, enum pipe unused) ++{ ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ ++ return intel_de_read(dev_priv, BLC_PWM_PCH_CTL2) & BACKLIGHT_DUTY_CYCLE_MASK; ++} ++ ++static u32 pch_get_backlight(struct intel_connector *connector, enum pipe unused) ++{ ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ ++ return intel_de_read(dev_priv, BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; ++} ++ ++static u32 i9xx_get_backlight(struct intel_connector *connector, enum pipe unused) ++{ ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ struct intel_panel *panel = &connector->panel; ++ u32 val; ++ ++ val = intel_de_read(dev_priv, BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; ++ if (DISPLAY_VER(dev_priv) < 4) ++ val >>= 1; ++ ++ if (panel->backlight.combination_mode) { ++ u8 lbpc; ++ ++ pci_read_config_byte(to_pci_dev(dev_priv->drm.dev), LBPC, &lbpc); ++ val *= lbpc; ++ } ++ ++ return val; ++} ++ ++static u32 vlv_get_backlight(struct intel_connector *connector, enum pipe pipe) ++{ ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ ++ if (drm_WARN_ON(&dev_priv->drm, pipe != PIPE_A && pipe != PIPE_B)) ++ return 0; ++ ++ return intel_de_read(dev_priv, VLV_BLC_PWM_CTL(pipe)) & BACKLIGHT_DUTY_CYCLE_MASK; ++} ++ ++static u32 bxt_get_backlight(struct intel_connector *connector, enum pipe unused) ++{ ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ struct intel_panel *panel = &connector->panel; ++ ++ return intel_de_read(dev_priv, ++ BXT_BLC_PWM_DUTY(panel->backlight.controller)); ++} ++ ++static u32 ext_pwm_get_backlight(struct intel_connector *connector, enum pipe unused) ++{ ++ struct intel_panel *panel = &connector->panel; ++ struct pwm_state state; ++ ++ pwm_get_state(panel->backlight.pwm, &state); ++ return pwm_get_relative_duty_cycle(&state, 100); ++} ++ ++static void lpt_set_backlight(const struct drm_connector_state *conn_state, u32 level) ++{ ++ struct intel_connector *connector = to_intel_connector(conn_state->connector); ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ ++ u32 val = intel_de_read(dev_priv, BLC_PWM_PCH_CTL2) & ~BACKLIGHT_DUTY_CYCLE_MASK; ++ intel_de_write(dev_priv, BLC_PWM_PCH_CTL2, val | level); ++} ++ ++static void pch_set_backlight(const struct drm_connector_state *conn_state, u32 level) ++{ ++ struct intel_connector *connector = to_intel_connector(conn_state->connector); ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ u32 tmp; ++ ++ tmp = intel_de_read(dev_priv, BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK; ++ intel_de_write(dev_priv, BLC_PWM_CPU_CTL, tmp | level); ++} ++ ++static void i9xx_set_backlight(const struct drm_connector_state *conn_state, u32 level) ++{ ++ struct intel_connector *connector = to_intel_connector(conn_state->connector); ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ struct intel_panel *panel = &connector->panel; ++ u32 tmp, mask; ++ ++ drm_WARN_ON(&dev_priv->drm, panel->backlight.pwm_level_max == 0); ++ ++ if (panel->backlight.combination_mode) { ++ u8 lbpc; ++ ++ lbpc = level * 0xfe / panel->backlight.pwm_level_max + 1; ++ level /= lbpc; ++ pci_write_config_byte(to_pci_dev(dev_priv->drm.dev), LBPC, lbpc); ++ } ++ ++ if (DISPLAY_VER(dev_priv) == 4) { ++ mask = BACKLIGHT_DUTY_CYCLE_MASK; ++ } else { ++ level <<= 1; ++ mask = BACKLIGHT_DUTY_CYCLE_MASK_PNV; ++ } ++ ++ tmp = intel_de_read(dev_priv, BLC_PWM_CTL) & ~mask; ++ intel_de_write(dev_priv, BLC_PWM_CTL, tmp | level); ++} ++ ++static void vlv_set_backlight(const struct drm_connector_state *conn_state, u32 level) ++{ ++ struct intel_connector *connector = to_intel_connector(conn_state->connector); ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ enum pipe pipe = to_intel_crtc(conn_state->crtc)->pipe; ++ u32 tmp; ++ ++ tmp = intel_de_read(dev_priv, VLV_BLC_PWM_CTL(pipe)) & ~BACKLIGHT_DUTY_CYCLE_MASK; ++ intel_de_write(dev_priv, VLV_BLC_PWM_CTL(pipe), tmp | level); ++} ++ ++static void bxt_set_backlight(const struct drm_connector_state *conn_state, u32 level) ++{ ++ struct intel_connector *connector = to_intel_connector(conn_state->connector); ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ struct intel_panel *panel = &connector->panel; ++ ++ intel_de_write(dev_priv, ++ BXT_BLC_PWM_DUTY(panel->backlight.controller), level); ++} ++ ++static void ext_pwm_set_backlight(const struct drm_connector_state *conn_state, u32 level) ++{ ++ struct intel_panel *panel = &to_intel_connector(conn_state->connector)->panel; ++ ++ pwm_set_relative_duty_cycle(&panel->backlight.pwm_state, level, 100); ++ pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state); ++} ++ ++static void ++intel_panel_actually_set_backlight(const struct drm_connector_state *conn_state, u32 level) ++{ ++ struct intel_connector *connector = to_intel_connector(conn_state->connector); ++ struct drm_i915_private *i915 = to_i915(connector->base.dev); ++ struct intel_panel *panel = &connector->panel; ++ ++ drm_dbg_kms(&i915->drm, "set backlight level = %d\n", level); ++ ++ panel->backlight.funcs->set(conn_state, level); ++} ++ ++/* set backlight brightness to level in range [0..max], assuming hw min is ++ * respected. ++ */ ++void intel_panel_set_backlight_acpi(const struct drm_connector_state *conn_state, ++ u32 user_level, u32 user_max) ++{ ++ struct intel_connector *connector = to_intel_connector(conn_state->connector); ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ struct intel_panel *panel = &connector->panel; ++ u32 hw_level; ++ ++ /* ++ * Lack of crtc may occur during driver init because ++ * connection_mutex isn't held across the entire backlight ++ * setup + modeset readout, and the BIOS can issue the ++ * requests at any time. ++ */ ++ if (!panel->backlight.present || !conn_state->crtc) ++ return; ++ ++ mutex_lock(&dev_priv->backlight_lock); ++ ++ drm_WARN_ON(&dev_priv->drm, panel->backlight.max == 0); ++ ++ hw_level = clamp_user_to_hw(connector, user_level, user_max); ++ panel->backlight.level = hw_level; ++ ++ if (panel->backlight.device) ++ panel->backlight.device->props.brightness = ++ scale_hw_to_user(connector, ++ panel->backlight.level, ++ panel->backlight.device->props.max_brightness); ++ ++ if (panel->backlight.enabled) ++ intel_panel_actually_set_backlight(conn_state, hw_level); ++ ++ mutex_unlock(&dev_priv->backlight_lock); ++} ++ ++static void lpt_disable_backlight(const struct drm_connector_state *old_conn_state, u32 level) ++{ ++ struct intel_connector *connector = to_intel_connector(old_conn_state->connector); ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ u32 tmp; ++ ++ intel_panel_set_pwm_level(old_conn_state, level); ++ ++ /* ++ * Although we don't support or enable CPU PWM with LPT/SPT based ++ * systems, it may have been enabled prior to loading the ++ * driver. Disable to avoid warnings on LCPLL disable. ++ * ++ * This needs rework if we need to add support for CPU PWM on PCH split ++ * platforms. ++ */ ++ tmp = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2); ++ if (tmp & BLM_PWM_ENABLE) { ++ drm_dbg_kms(&dev_priv->drm, ++ "cpu backlight was enabled, disabling\n"); ++ intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, ++ tmp & ~BLM_PWM_ENABLE); ++ } ++ ++ tmp = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1); ++ intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, tmp & ~BLM_PCH_PWM_ENABLE); ++} ++ ++static void pch_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val) ++{ ++ struct intel_connector *connector = to_intel_connector(old_conn_state->connector); ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ u32 tmp; ++ ++ intel_panel_set_pwm_level(old_conn_state, val); ++ ++ tmp = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2); ++ intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, tmp & ~BLM_PWM_ENABLE); ++ ++ tmp = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1); ++ intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, tmp & ~BLM_PCH_PWM_ENABLE); ++} ++ ++static void i9xx_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val) ++{ ++ intel_panel_set_pwm_level(old_conn_state, val); ++} ++ ++static void i965_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val) ++{ ++ struct drm_i915_private *dev_priv = to_i915(old_conn_state->connector->dev); ++ u32 tmp; ++ ++ intel_panel_set_pwm_level(old_conn_state, val); ++ ++ tmp = intel_de_read(dev_priv, BLC_PWM_CTL2); ++ intel_de_write(dev_priv, BLC_PWM_CTL2, tmp & ~BLM_PWM_ENABLE); ++} ++ ++static void vlv_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val) ++{ ++ struct intel_connector *connector = to_intel_connector(old_conn_state->connector); ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ enum pipe pipe = to_intel_crtc(old_conn_state->crtc)->pipe; ++ u32 tmp; ++ ++ intel_panel_set_pwm_level(old_conn_state, val); ++ ++ tmp = intel_de_read(dev_priv, VLV_BLC_PWM_CTL2(pipe)); ++ intel_de_write(dev_priv, VLV_BLC_PWM_CTL2(pipe), ++ tmp & ~BLM_PWM_ENABLE); ++} ++ ++static void bxt_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val) ++{ ++ struct intel_connector *connector = to_intel_connector(old_conn_state->connector); ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ struct intel_panel *panel = &connector->panel; ++ u32 tmp; ++ ++ intel_panel_set_pwm_level(old_conn_state, val); ++ ++ tmp = intel_de_read(dev_priv, ++ BXT_BLC_PWM_CTL(panel->backlight.controller)); ++ intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller), ++ tmp & ~BXT_BLC_PWM_ENABLE); ++ ++ if (panel->backlight.controller == 1) { ++ val = intel_de_read(dev_priv, UTIL_PIN_CTL); ++ val &= ~UTIL_PIN_ENABLE; ++ intel_de_write(dev_priv, UTIL_PIN_CTL, val); ++ } ++} ++ ++static void cnp_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val) ++{ ++ struct intel_connector *connector = to_intel_connector(old_conn_state->connector); ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ struct intel_panel *panel = &connector->panel; ++ u32 tmp; ++ ++ intel_panel_set_pwm_level(old_conn_state, val); ++ ++ tmp = intel_de_read(dev_priv, ++ BXT_BLC_PWM_CTL(panel->backlight.controller)); ++ intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller), ++ tmp & ~BXT_BLC_PWM_ENABLE); ++} ++ ++static void ext_pwm_disable_backlight(const struct drm_connector_state *old_conn_state, u32 level) ++{ ++ struct intel_connector *connector = to_intel_connector(old_conn_state->connector); ++ struct intel_panel *panel = &connector->panel; ++ ++ panel->backlight.pwm_state.enabled = false; ++ pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state); ++} ++ ++void intel_panel_disable_backlight(const struct drm_connector_state *old_conn_state) ++{ ++ struct intel_connector *connector = to_intel_connector(old_conn_state->connector); ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ struct intel_panel *panel = &connector->panel; ++ ++ if (!panel->backlight.present) ++ return; ++ ++ /* ++ * Do not disable backlight on the vga_switcheroo path. When switching ++ * away from i915, the other client may depend on i915 to handle the ++ * backlight. This will leave the backlight on unnecessarily when ++ * another client is not activated. ++ */ ++ if (dev_priv->drm.switch_power_state == DRM_SWITCH_POWER_CHANGING) { ++ drm_dbg_kms(&dev_priv->drm, ++ "Skipping backlight disable on vga switch\n"); ++ return; ++ } ++ ++ mutex_lock(&dev_priv->backlight_lock); ++ ++ if (panel->backlight.device) ++ panel->backlight.device->props.power = FB_BLANK_POWERDOWN; ++ panel->backlight.enabled = false; ++ panel->backlight.funcs->disable(old_conn_state, 0); ++ ++ mutex_unlock(&dev_priv->backlight_lock); ++} ++ ++static void lpt_enable_backlight(const struct intel_crtc_state *crtc_state, ++ const struct drm_connector_state *conn_state, u32 level) ++{ ++ struct intel_connector *connector = to_intel_connector(conn_state->connector); ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ struct intel_panel *panel = &connector->panel; ++ u32 pch_ctl1, pch_ctl2, schicken; ++ ++ pch_ctl1 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1); ++ if (pch_ctl1 & BLM_PCH_PWM_ENABLE) { ++ drm_dbg_kms(&dev_priv->drm, "pch backlight already enabled\n"); ++ pch_ctl1 &= ~BLM_PCH_PWM_ENABLE; ++ intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, pch_ctl1); ++ } ++ ++ if (HAS_PCH_LPT(dev_priv)) { ++ schicken = intel_de_read(dev_priv, SOUTH_CHICKEN2); ++ if (panel->backlight.alternate_pwm_increment) ++ schicken |= LPT_PWM_GRANULARITY; ++ else ++ schicken &= ~LPT_PWM_GRANULARITY; ++ intel_de_write(dev_priv, SOUTH_CHICKEN2, schicken); ++ } else { ++ schicken = intel_de_read(dev_priv, SOUTH_CHICKEN1); ++ if (panel->backlight.alternate_pwm_increment) ++ schicken |= SPT_PWM_GRANULARITY; ++ else ++ schicken &= ~SPT_PWM_GRANULARITY; ++ intel_de_write(dev_priv, SOUTH_CHICKEN1, schicken); ++ } ++ ++ pch_ctl2 = panel->backlight.pwm_level_max << 16; ++ intel_de_write(dev_priv, BLC_PWM_PCH_CTL2, pch_ctl2); ++ ++ pch_ctl1 = 0; ++ if (panel->backlight.active_low_pwm) ++ pch_ctl1 |= BLM_PCH_POLARITY; ++ ++ /* After LPT, override is the default. */ ++ if (HAS_PCH_LPT(dev_priv)) ++ pch_ctl1 |= BLM_PCH_OVERRIDE_ENABLE; ++ ++ intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, pch_ctl1); ++ intel_de_posting_read(dev_priv, BLC_PWM_PCH_CTL1); ++ intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, ++ pch_ctl1 | BLM_PCH_PWM_ENABLE); ++ ++ /* This won't stick until the above enable. */ ++ intel_panel_set_pwm_level(conn_state, level); ++} ++ ++static void pch_enable_backlight(const struct intel_crtc_state *crtc_state, ++ const struct drm_connector_state *conn_state, u32 level) ++{ ++ struct intel_connector *connector = to_intel_connector(conn_state->connector); ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ struct intel_panel *panel = &connector->panel; ++ enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; ++ u32 cpu_ctl2, pch_ctl1, pch_ctl2; ++ ++ cpu_ctl2 = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2); ++ if (cpu_ctl2 & BLM_PWM_ENABLE) { ++ drm_dbg_kms(&dev_priv->drm, "cpu backlight already enabled\n"); ++ cpu_ctl2 &= ~BLM_PWM_ENABLE; ++ intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, cpu_ctl2); ++ } ++ ++ pch_ctl1 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1); ++ if (pch_ctl1 & BLM_PCH_PWM_ENABLE) { ++ drm_dbg_kms(&dev_priv->drm, "pch backlight already enabled\n"); ++ pch_ctl1 &= ~BLM_PCH_PWM_ENABLE; ++ intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, pch_ctl1); ++ } ++ ++ if (cpu_transcoder == TRANSCODER_EDP) ++ cpu_ctl2 = BLM_TRANSCODER_EDP; ++ else ++ cpu_ctl2 = BLM_PIPE(cpu_transcoder); ++ intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, cpu_ctl2); ++ intel_de_posting_read(dev_priv, BLC_PWM_CPU_CTL2); ++ intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, cpu_ctl2 | BLM_PWM_ENABLE); ++ ++ /* This won't stick until the above enable. */ ++ intel_panel_set_pwm_level(conn_state, level); ++ ++ pch_ctl2 = panel->backlight.pwm_level_max << 16; ++ intel_de_write(dev_priv, BLC_PWM_PCH_CTL2, pch_ctl2); ++ ++ pch_ctl1 = 0; ++ if (panel->backlight.active_low_pwm) ++ pch_ctl1 |= BLM_PCH_POLARITY; ++ ++ intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, pch_ctl1); ++ intel_de_posting_read(dev_priv, BLC_PWM_PCH_CTL1); ++ intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, ++ pch_ctl1 | BLM_PCH_PWM_ENABLE); ++} ++ ++static void i9xx_enable_backlight(const struct intel_crtc_state *crtc_state, ++ const struct drm_connector_state *conn_state, u32 level) ++{ ++ struct intel_connector *connector = to_intel_connector(conn_state->connector); ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ struct intel_panel *panel = &connector->panel; ++ u32 ctl, freq; ++ ++ ctl = intel_de_read(dev_priv, BLC_PWM_CTL); ++ if (ctl & BACKLIGHT_DUTY_CYCLE_MASK_PNV) { ++ drm_dbg_kms(&dev_priv->drm, "backlight already enabled\n"); ++ intel_de_write(dev_priv, BLC_PWM_CTL, 0); ++ } ++ ++ freq = panel->backlight.pwm_level_max; ++ if (panel->backlight.combination_mode) ++ freq /= 0xff; ++ ++ ctl = freq << 17; ++ if (panel->backlight.combination_mode) ++ ctl |= BLM_LEGACY_MODE; ++ if (IS_PINEVIEW(dev_priv) && panel->backlight.active_low_pwm) ++ ctl |= BLM_POLARITY_PNV; ++ ++ intel_de_write(dev_priv, BLC_PWM_CTL, ctl); ++ intel_de_posting_read(dev_priv, BLC_PWM_CTL); ++ ++ /* XXX: combine this into above write? */ ++ intel_panel_set_pwm_level(conn_state, level); ++ ++ /* ++ * Needed to enable backlight on some 855gm models. BLC_HIST_CTL is ++ * 855gm only, but checking for gen2 is safe, as 855gm is the only gen2 ++ * that has backlight. ++ */ ++ if (DISPLAY_VER(dev_priv) == 2) ++ intel_de_write(dev_priv, BLC_HIST_CTL, BLM_HISTOGRAM_ENABLE); ++} ++ ++static void i965_enable_backlight(const struct intel_crtc_state *crtc_state, ++ const struct drm_connector_state *conn_state, u32 level) ++{ ++ struct intel_connector *connector = to_intel_connector(conn_state->connector); ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ struct intel_panel *panel = &connector->panel; ++ enum pipe pipe = to_intel_crtc(conn_state->crtc)->pipe; ++ u32 ctl, ctl2, freq; ++ ++ ctl2 = intel_de_read(dev_priv, BLC_PWM_CTL2); ++ if (ctl2 & BLM_PWM_ENABLE) { ++ drm_dbg_kms(&dev_priv->drm, "backlight already enabled\n"); ++ ctl2 &= ~BLM_PWM_ENABLE; ++ intel_de_write(dev_priv, BLC_PWM_CTL2, ctl2); ++ } ++ ++ freq = panel->backlight.pwm_level_max; ++ if (panel->backlight.combination_mode) ++ freq /= 0xff; ++ ++ ctl = freq << 16; ++ intel_de_write(dev_priv, BLC_PWM_CTL, ctl); ++ ++ ctl2 = BLM_PIPE(pipe); ++ if (panel->backlight.combination_mode) ++ ctl2 |= BLM_COMBINATION_MODE; ++ if (panel->backlight.active_low_pwm) ++ ctl2 |= BLM_POLARITY_I965; ++ intel_de_write(dev_priv, BLC_PWM_CTL2, ctl2); ++ intel_de_posting_read(dev_priv, BLC_PWM_CTL2); ++ intel_de_write(dev_priv, BLC_PWM_CTL2, ctl2 | BLM_PWM_ENABLE); ++ ++ intel_panel_set_pwm_level(conn_state, level); ++} ++ ++static void vlv_enable_backlight(const struct intel_crtc_state *crtc_state, ++ const struct drm_connector_state *conn_state, u32 level) ++{ ++ struct intel_connector *connector = to_intel_connector(conn_state->connector); ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ struct intel_panel *panel = &connector->panel; ++ enum pipe pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe; ++ u32 ctl, ctl2; ++ ++ ctl2 = intel_de_read(dev_priv, VLV_BLC_PWM_CTL2(pipe)); ++ if (ctl2 & BLM_PWM_ENABLE) { ++ drm_dbg_kms(&dev_priv->drm, "backlight already enabled\n"); ++ ctl2 &= ~BLM_PWM_ENABLE; ++ intel_de_write(dev_priv, VLV_BLC_PWM_CTL2(pipe), ctl2); ++ } ++ ++ ctl = panel->backlight.pwm_level_max << 16; ++ intel_de_write(dev_priv, VLV_BLC_PWM_CTL(pipe), ctl); ++ ++ /* XXX: combine this into above write? */ ++ intel_panel_set_pwm_level(conn_state, level); ++ ++ ctl2 = 0; ++ if (panel->backlight.active_low_pwm) ++ ctl2 |= BLM_POLARITY_I965; ++ intel_de_write(dev_priv, VLV_BLC_PWM_CTL2(pipe), ctl2); ++ intel_de_posting_read(dev_priv, VLV_BLC_PWM_CTL2(pipe)); ++ intel_de_write(dev_priv, VLV_BLC_PWM_CTL2(pipe), ++ ctl2 | BLM_PWM_ENABLE); ++} ++ ++static void bxt_enable_backlight(const struct intel_crtc_state *crtc_state, ++ const struct drm_connector_state *conn_state, u32 level) ++{ ++ struct intel_connector *connector = to_intel_connector(conn_state->connector); ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ struct intel_panel *panel = &connector->panel; ++ enum pipe pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe; ++ u32 pwm_ctl, val; ++ ++ /* Controller 1 uses the utility pin. */ ++ if (panel->backlight.controller == 1) { ++ val = intel_de_read(dev_priv, UTIL_PIN_CTL); ++ if (val & UTIL_PIN_ENABLE) { ++ drm_dbg_kms(&dev_priv->drm, ++ "util pin already enabled\n"); ++ val &= ~UTIL_PIN_ENABLE; ++ intel_de_write(dev_priv, UTIL_PIN_CTL, val); ++ } ++ ++ val = 0; ++ if (panel->backlight.util_pin_active_low) ++ val |= UTIL_PIN_POLARITY; ++ intel_de_write(dev_priv, UTIL_PIN_CTL, ++ val | UTIL_PIN_PIPE(pipe) | UTIL_PIN_MODE_PWM | UTIL_PIN_ENABLE); ++ } ++ ++ pwm_ctl = intel_de_read(dev_priv, ++ BXT_BLC_PWM_CTL(panel->backlight.controller)); ++ if (pwm_ctl & BXT_BLC_PWM_ENABLE) { ++ drm_dbg_kms(&dev_priv->drm, "backlight already enabled\n"); ++ pwm_ctl &= ~BXT_BLC_PWM_ENABLE; ++ intel_de_write(dev_priv, ++ BXT_BLC_PWM_CTL(panel->backlight.controller), ++ pwm_ctl); ++ } ++ ++ intel_de_write(dev_priv, ++ BXT_BLC_PWM_FREQ(panel->backlight.controller), ++ panel->backlight.pwm_level_max); ++ ++ intel_panel_set_pwm_level(conn_state, level); ++ ++ pwm_ctl = 0; ++ if (panel->backlight.active_low_pwm) ++ pwm_ctl |= BXT_BLC_PWM_POLARITY; ++ ++ intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller), ++ pwm_ctl); ++ intel_de_posting_read(dev_priv, ++ BXT_BLC_PWM_CTL(panel->backlight.controller)); ++ intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller), ++ pwm_ctl | BXT_BLC_PWM_ENABLE); ++} ++ ++static void cnp_enable_backlight(const struct intel_crtc_state *crtc_state, ++ const struct drm_connector_state *conn_state, u32 level) ++{ ++ struct intel_connector *connector = to_intel_connector(conn_state->connector); ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ struct intel_panel *panel = &connector->panel; ++ u32 pwm_ctl; ++ ++ pwm_ctl = intel_de_read(dev_priv, ++ BXT_BLC_PWM_CTL(panel->backlight.controller)); ++ if (pwm_ctl & BXT_BLC_PWM_ENABLE) { ++ drm_dbg_kms(&dev_priv->drm, "backlight already enabled\n"); ++ pwm_ctl &= ~BXT_BLC_PWM_ENABLE; ++ intel_de_write(dev_priv, ++ BXT_BLC_PWM_CTL(panel->backlight.controller), ++ pwm_ctl); ++ } ++ ++ intel_de_write(dev_priv, ++ BXT_BLC_PWM_FREQ(panel->backlight.controller), ++ panel->backlight.pwm_level_max); ++ ++ intel_panel_set_pwm_level(conn_state, level); ++ ++ pwm_ctl = 0; ++ if (panel->backlight.active_low_pwm) ++ pwm_ctl |= BXT_BLC_PWM_POLARITY; ++ ++ intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller), ++ pwm_ctl); ++ intel_de_posting_read(dev_priv, ++ BXT_BLC_PWM_CTL(panel->backlight.controller)); ++ intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller), ++ pwm_ctl | BXT_BLC_PWM_ENABLE); ++} ++ ++static void ext_pwm_enable_backlight(const struct intel_crtc_state *crtc_state, ++ const struct drm_connector_state *conn_state, u32 level) ++{ ++ struct intel_connector *connector = to_intel_connector(conn_state->connector); ++ struct intel_panel *panel = &connector->panel; ++ ++ pwm_set_relative_duty_cycle(&panel->backlight.pwm_state, level, 100); ++ panel->backlight.pwm_state.enabled = true; ++ pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state); ++} ++ ++static void __intel_panel_enable_backlight(const struct intel_crtc_state *crtc_state, ++ const struct drm_connector_state *conn_state) ++{ ++ struct intel_connector *connector = to_intel_connector(conn_state->connector); ++ struct intel_panel *panel = &connector->panel; ++ ++ WARN_ON(panel->backlight.max == 0); ++ ++ if (panel->backlight.level <= panel->backlight.min) { ++ panel->backlight.level = panel->backlight.max; ++ if (panel->backlight.device) ++ panel->backlight.device->props.brightness = ++ scale_hw_to_user(connector, ++ panel->backlight.level, ++ panel->backlight.device->props.max_brightness); ++ } ++ ++ panel->backlight.funcs->enable(crtc_state, conn_state, panel->backlight.level); ++ panel->backlight.enabled = true; ++ if (panel->backlight.device) ++ panel->backlight.device->props.power = FB_BLANK_UNBLANK; ++} ++ ++void intel_panel_enable_backlight(const struct intel_crtc_state *crtc_state, ++ const struct drm_connector_state *conn_state) ++{ ++ struct intel_connector *connector = to_intel_connector(conn_state->connector); ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ struct intel_panel *panel = &connector->panel; ++ enum pipe pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe; ++ ++ if (!panel->backlight.present) ++ return; ++ ++ drm_dbg_kms(&dev_priv->drm, "pipe %c\n", pipe_name(pipe)); ++ ++ mutex_lock(&dev_priv->backlight_lock); ++ ++ __intel_panel_enable_backlight(crtc_state, conn_state); ++ ++ mutex_unlock(&dev_priv->backlight_lock); ++} ++ ++#if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE) ++static u32 intel_panel_get_backlight(struct intel_connector *connector) ++{ ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ struct intel_panel *panel = &connector->panel; ++ u32 val = 0; ++ ++ mutex_lock(&dev_priv->backlight_lock); ++ ++ if (panel->backlight.enabled) ++ val = panel->backlight.funcs->get(connector, intel_connector_get_pipe(connector)); ++ ++ mutex_unlock(&dev_priv->backlight_lock); ++ ++ drm_dbg_kms(&dev_priv->drm, "get backlight PWM = %d\n", val); ++ return val; ++} ++ ++/* Scale user_level in range [0..user_max] to [hw_min..hw_max]. */ ++static u32 scale_user_to_hw(struct intel_connector *connector, ++ u32 user_level, u32 user_max) ++{ ++ struct intel_panel *panel = &connector->panel; ++ ++ return scale(user_level, 0, user_max, ++ panel->backlight.min, panel->backlight.max); ++} ++ ++/* set backlight brightness to level in range [0..max], scaling wrt hw min */ ++static void intel_panel_set_backlight(const struct drm_connector_state *conn_state, ++ u32 user_level, u32 user_max) ++{ ++ struct intel_connector *connector = to_intel_connector(conn_state->connector); ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ struct intel_panel *panel = &connector->panel; ++ u32 hw_level; ++ ++ if (!panel->backlight.present) ++ return; ++ ++ mutex_lock(&dev_priv->backlight_lock); ++ ++ drm_WARN_ON(&dev_priv->drm, panel->backlight.max == 0); ++ ++ hw_level = scale_user_to_hw(connector, user_level, user_max); ++ panel->backlight.level = hw_level; ++ ++ if (panel->backlight.enabled) ++ intel_panel_actually_set_backlight(conn_state, hw_level); ++ ++ mutex_unlock(&dev_priv->backlight_lock); ++} ++ ++static int intel_backlight_device_update_status(struct backlight_device *bd) ++{ ++ struct intel_connector *connector = bl_get_data(bd); ++ struct intel_panel *panel = &connector->panel; ++ struct drm_device *dev = connector->base.dev; ++ ++ drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); ++ DRM_DEBUG_KMS("updating intel_backlight, brightness=%d/%d\n", ++ bd->props.brightness, bd->props.max_brightness); ++ intel_panel_set_backlight(connector->base.state, bd->props.brightness, ++ bd->props.max_brightness); ++ ++ /* ++ * Allow flipping bl_power as a sub-state of enabled. Sadly the ++ * backlight class device does not make it easy to differentiate ++ * between callbacks for brightness and bl_power, so our backlight_power ++ * callback needs to take this into account. ++ */ ++ if (panel->backlight.enabled) { ++ if (panel->backlight.power) { ++ bool enable = bd->props.power == FB_BLANK_UNBLANK && ++ bd->props.brightness != 0; ++ panel->backlight.power(connector, enable); ++ } ++ } else { ++ bd->props.power = FB_BLANK_POWERDOWN; ++ } ++ ++ drm_modeset_unlock(&dev->mode_config.connection_mutex); ++ return 0; ++} ++ ++static int intel_backlight_device_get_brightness(struct backlight_device *bd) ++{ ++ struct intel_connector *connector = bl_get_data(bd); ++ struct drm_device *dev = connector->base.dev; ++ struct drm_i915_private *dev_priv = to_i915(dev); ++ intel_wakeref_t wakeref; ++ int ret = 0; ++ ++ with_intel_runtime_pm(&dev_priv->runtime_pm, wakeref) { ++ u32 hw_level; ++ ++ drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); ++ ++ hw_level = intel_panel_get_backlight(connector); ++ ret = scale_hw_to_user(connector, ++ hw_level, bd->props.max_brightness); ++ ++ drm_modeset_unlock(&dev->mode_config.connection_mutex); ++ } ++ ++ return ret; ++} ++ ++static const struct backlight_ops intel_backlight_device_ops = { ++ .update_status = intel_backlight_device_update_status, ++ .get_brightness = intel_backlight_device_get_brightness, ++}; ++ ++int intel_backlight_device_register(struct intel_connector *connector) ++{ ++ struct drm_i915_private *i915 = to_i915(connector->base.dev); ++ struct intel_panel *panel = &connector->panel; ++ struct backlight_properties props; ++ struct backlight_device *bd; ++ const char *name; ++ int ret = 0; ++ ++ if (WARN_ON(panel->backlight.device)) ++ return -ENODEV; ++ ++ if (!panel->backlight.present) ++ return 0; ++ ++ WARN_ON(panel->backlight.max == 0); ++ ++ memset(&props, 0, sizeof(props)); ++ props.type = BACKLIGHT_RAW; ++ ++ /* ++ * Note: Everything should work even if the backlight device max ++ * presented to the userspace is arbitrarily chosen. ++ */ ++ props.max_brightness = panel->backlight.max; ++ props.brightness = scale_hw_to_user(connector, ++ panel->backlight.level, ++ props.max_brightness); ++ ++ if (panel->backlight.enabled) ++ props.power = FB_BLANK_UNBLANK; ++ else ++ props.power = FB_BLANK_POWERDOWN; ++ ++ name = kstrdup("intel_backlight", GFP_KERNEL); ++ if (!name) ++ return -ENOMEM; ++ ++ bd = backlight_device_get_by_name(name); ++ if (bd) { ++ put_device(&bd->dev); ++ /* ++ * Using the same name independent of the drm device or connector ++ * prevents registration of multiple backlight devices in the ++ * driver. However, we need to use the default name for backward ++ * compatibility. Use unique names for subsequent backlight devices as a ++ * fallback when the default name already exists. ++ */ ++ kfree(name); ++ name = kasprintf(GFP_KERNEL, "card%d-%s-backlight", ++ i915->drm.primary->index, connector->base.name); ++ if (!name) ++ return -ENOMEM; ++ } ++ bd = backlight_device_register(name, connector->base.kdev, connector, ++ &intel_backlight_device_ops, &props); ++ ++ if (IS_ERR(bd)) { ++ drm_err(&i915->drm, ++ "[CONNECTOR:%d:%s] backlight device %s register failed: %ld\n", ++ connector->base.base.id, connector->base.name, name, PTR_ERR(bd)); ++ ret = PTR_ERR(bd); ++ goto out; ++ } ++ ++ panel->backlight.device = bd; ++ ++ drm_dbg_kms(&i915->drm, ++ "[CONNECTOR:%d:%s] backlight device %s registered\n", ++ connector->base.base.id, connector->base.name, name); ++ ++out: ++ kfree(name); ++ ++ return ret; ++} ++ ++void intel_backlight_device_unregister(struct intel_connector *connector) ++{ ++ struct intel_panel *panel = &connector->panel; ++ ++ if (panel->backlight.device) { ++ backlight_device_unregister(panel->backlight.device); ++ panel->backlight.device = NULL; ++ } ++} ++#endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */ ++ ++/* ++ * CNP: PWM clock frequency is 19.2 MHz or 24 MHz. ++ * PWM increment = 1 ++ */ ++static u32 cnp_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz) ++{ ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ ++ return DIV_ROUND_CLOSEST(KHz(RUNTIME_INFO(dev_priv)->rawclk_freq), ++ pwm_freq_hz); ++} ++ ++/* ++ * BXT: PWM clock frequency = 19.2 MHz. ++ */ ++static u32 bxt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz) ++{ ++ return DIV_ROUND_CLOSEST(KHz(19200), pwm_freq_hz); ++} ++ ++/* ++ * SPT: This value represents the period of the PWM stream in clock periods ++ * multiplied by 16 (default increment) or 128 (alternate increment selected in ++ * SCHICKEN_1 bit 0). PWM clock is 24 MHz. ++ */ ++static u32 spt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz) ++{ ++ struct intel_panel *panel = &connector->panel; ++ u32 mul; ++ ++ if (panel->backlight.alternate_pwm_increment) ++ mul = 128; ++ else ++ mul = 16; ++ ++ return DIV_ROUND_CLOSEST(MHz(24), pwm_freq_hz * mul); ++} ++ ++/* ++ * LPT: This value represents the period of the PWM stream in clock periods ++ * multiplied by 128 (default increment) or 16 (alternate increment, selected in ++ * LPT SOUTH_CHICKEN2 register bit 5). ++ */ ++static u32 lpt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz) ++{ ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ struct intel_panel *panel = &connector->panel; ++ u32 mul, clock; ++ ++ if (panel->backlight.alternate_pwm_increment) ++ mul = 16; ++ else ++ mul = 128; ++ ++ if (HAS_PCH_LPT_H(dev_priv)) ++ clock = MHz(135); /* LPT:H */ ++ else ++ clock = MHz(24); /* LPT:LP */ ++ ++ return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * mul); ++} ++ ++/* ++ * ILK/SNB/IVB: This value represents the period of the PWM stream in PCH ++ * display raw clocks multiplied by 128. ++ */ ++static u32 pch_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz) ++{ ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ ++ return DIV_ROUND_CLOSEST(KHz(RUNTIME_INFO(dev_priv)->rawclk_freq), ++ pwm_freq_hz * 128); ++} ++ ++/* ++ * Gen2: This field determines the number of time base events (display core ++ * clock frequency/32) in total for a complete cycle of modulated backlight ++ * control. ++ * ++ * Gen3: A time base event equals the display core clock ([DevPNV] HRAW clock) ++ * divided by 32. ++ */ ++static u32 i9xx_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz) ++{ ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ int clock; ++ ++ if (IS_PINEVIEW(dev_priv)) ++ clock = KHz(RUNTIME_INFO(dev_priv)->rawclk_freq); ++ else ++ clock = KHz(dev_priv->cdclk.hw.cdclk); ++ ++ return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * 32); ++} ++ ++/* ++ * Gen4: This value represents the period of the PWM stream in display core ++ * clocks ([DevCTG] HRAW clocks) multiplied by 128. ++ * ++ */ ++static u32 i965_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz) ++{ ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ int clock; ++ ++ if (IS_G4X(dev_priv)) ++ clock = KHz(RUNTIME_INFO(dev_priv)->rawclk_freq); ++ else ++ clock = KHz(dev_priv->cdclk.hw.cdclk); ++ ++ return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * 128); ++} ++ ++/* ++ * VLV: This value represents the period of the PWM stream in display core ++ * clocks ([DevCTG] 200MHz HRAW clocks) multiplied by 128 or 25MHz S0IX clocks ++ * multiplied by 16. CHV uses a 19.2MHz S0IX clock. ++ */ ++static u32 vlv_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz) ++{ ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ int mul, clock; ++ ++ if ((intel_de_read(dev_priv, CBR1_VLV) & CBR_PWM_CLOCK_MUX_SELECT) == 0) { ++ if (IS_CHERRYVIEW(dev_priv)) ++ clock = KHz(19200); ++ else ++ clock = MHz(25); ++ mul = 16; ++ } else { ++ clock = KHz(RUNTIME_INFO(dev_priv)->rawclk_freq); ++ mul = 128; ++ } ++ ++ return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * mul); ++} ++ ++static u16 get_vbt_pwm_freq(struct drm_i915_private *dev_priv) ++{ ++ u16 pwm_freq_hz = dev_priv->vbt.backlight.pwm_freq_hz; ++ ++ if (pwm_freq_hz) { ++ drm_dbg_kms(&dev_priv->drm, ++ "VBT defined backlight frequency %u Hz\n", ++ pwm_freq_hz); ++ } else { ++ pwm_freq_hz = 200; ++ drm_dbg_kms(&dev_priv->drm, ++ "default backlight frequency %u Hz\n", ++ pwm_freq_hz); ++ } ++ ++ return pwm_freq_hz; ++} ++ ++static u32 get_backlight_max_vbt(struct intel_connector *connector) ++{ ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ struct intel_panel *panel = &connector->panel; ++ u16 pwm_freq_hz = get_vbt_pwm_freq(dev_priv); ++ u32 pwm; ++ ++ if (!panel->backlight.pwm_funcs->hz_to_pwm) { ++ drm_dbg_kms(&dev_priv->drm, ++ "backlight frequency conversion not supported\n"); ++ return 0; ++ } ++ ++ pwm = panel->backlight.pwm_funcs->hz_to_pwm(connector, pwm_freq_hz); ++ if (!pwm) { ++ drm_dbg_kms(&dev_priv->drm, ++ "backlight frequency conversion failed\n"); ++ return 0; ++ } ++ ++ return pwm; ++} ++ ++/* ++ * Note: The setup hooks can't assume pipe is set! ++ */ ++static u32 get_backlight_min_vbt(struct intel_connector *connector) ++{ ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ struct intel_panel *panel = &connector->panel; ++ int min; ++ ++ drm_WARN_ON(&dev_priv->drm, panel->backlight.pwm_level_max == 0); ++ ++ /* ++ * XXX: If the vbt value is 255, it makes min equal to max, which leads ++ * to problems. There are such machines out there. Either our ++ * interpretation is wrong or the vbt has bogus data. Or both. Safeguard ++ * against this by letting the minimum be at most (arbitrarily chosen) ++ * 25% of the max. ++ */ ++ min = clamp_t(int, dev_priv->vbt.backlight.min_brightness, 0, 64); ++ if (min != dev_priv->vbt.backlight.min_brightness) { ++ drm_dbg_kms(&dev_priv->drm, ++ "clamping VBT min backlight %d/255 to %d/255\n", ++ dev_priv->vbt.backlight.min_brightness, min); ++ } ++ ++ /* vbt value is a coefficient in range [0..255] */ ++ return scale(min, 0, 255, 0, panel->backlight.pwm_level_max); ++} ++ ++static int lpt_setup_backlight(struct intel_connector *connector, enum pipe unused) ++{ ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ struct intel_panel *panel = &connector->panel; ++ u32 cpu_ctl2, pch_ctl1, pch_ctl2, val; ++ bool alt, cpu_mode; ++ ++ if (HAS_PCH_LPT(dev_priv)) ++ alt = intel_de_read(dev_priv, SOUTH_CHICKEN2) & LPT_PWM_GRANULARITY; ++ else ++ alt = intel_de_read(dev_priv, SOUTH_CHICKEN1) & SPT_PWM_GRANULARITY; ++ panel->backlight.alternate_pwm_increment = alt; ++ ++ pch_ctl1 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1); ++ panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY; ++ ++ pch_ctl2 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL2); ++ panel->backlight.pwm_level_max = pch_ctl2 >> 16; ++ ++ cpu_ctl2 = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2); ++ ++ if (!panel->backlight.pwm_level_max) ++ panel->backlight.pwm_level_max = get_backlight_max_vbt(connector); ++ ++ if (!panel->backlight.pwm_level_max) ++ return -ENODEV; ++ ++ panel->backlight.pwm_level_min = get_backlight_min_vbt(connector); ++ ++ panel->backlight.pwm_enabled = pch_ctl1 & BLM_PCH_PWM_ENABLE; ++ ++ cpu_mode = panel->backlight.pwm_enabled && HAS_PCH_LPT(dev_priv) && ++ !(pch_ctl1 & BLM_PCH_OVERRIDE_ENABLE) && ++ (cpu_ctl2 & BLM_PWM_ENABLE); ++ ++ if (cpu_mode) { ++ val = pch_get_backlight(connector, unused); ++ ++ drm_dbg_kms(&dev_priv->drm, ++ "CPU backlight register was enabled, switching to PCH override\n"); ++ ++ /* Write converted CPU PWM value to PCH override register */ ++ lpt_set_backlight(connector->base.state, val); ++ intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, ++ pch_ctl1 | BLM_PCH_OVERRIDE_ENABLE); ++ ++ intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, ++ cpu_ctl2 & ~BLM_PWM_ENABLE); ++ } ++ ++ return 0; ++} ++ ++static int pch_setup_backlight(struct intel_connector *connector, enum pipe unused) ++{ ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ struct intel_panel *panel = &connector->panel; ++ u32 cpu_ctl2, pch_ctl1, pch_ctl2; ++ ++ pch_ctl1 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1); ++ panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY; ++ ++ pch_ctl2 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL2); ++ panel->backlight.pwm_level_max = pch_ctl2 >> 16; ++ ++ if (!panel->backlight.pwm_level_max) ++ panel->backlight.pwm_level_max = get_backlight_max_vbt(connector); ++ ++ if (!panel->backlight.pwm_level_max) ++ return -ENODEV; ++ ++ panel->backlight.pwm_level_min = get_backlight_min_vbt(connector); ++ ++ cpu_ctl2 = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2); ++ panel->backlight.pwm_enabled = (cpu_ctl2 & BLM_PWM_ENABLE) && ++ (pch_ctl1 & BLM_PCH_PWM_ENABLE); ++ ++ return 0; ++} ++ ++static int i9xx_setup_backlight(struct intel_connector *connector, enum pipe unused) ++{ ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ struct intel_panel *panel = &connector->panel; ++ u32 ctl, val; ++ ++ ctl = intel_de_read(dev_priv, BLC_PWM_CTL); ++ ++ if (DISPLAY_VER(dev_priv) == 2 || IS_I915GM(dev_priv) || IS_I945GM(dev_priv)) ++ panel->backlight.combination_mode = ctl & BLM_LEGACY_MODE; ++ ++ if (IS_PINEVIEW(dev_priv)) ++ panel->backlight.active_low_pwm = ctl & BLM_POLARITY_PNV; ++ ++ panel->backlight.pwm_level_max = ctl >> 17; ++ ++ if (!panel->backlight.pwm_level_max) { ++ panel->backlight.pwm_level_max = get_backlight_max_vbt(connector); ++ panel->backlight.pwm_level_max >>= 1; ++ } ++ ++ if (!panel->backlight.pwm_level_max) ++ return -ENODEV; ++ ++ if (panel->backlight.combination_mode) ++ panel->backlight.pwm_level_max *= 0xff; ++ ++ panel->backlight.pwm_level_min = get_backlight_min_vbt(connector); ++ ++ val = i9xx_get_backlight(connector, unused); ++ val = intel_panel_invert_pwm_level(connector, val); ++ val = clamp(val, panel->backlight.pwm_level_min, panel->backlight.pwm_level_max); ++ ++ panel->backlight.pwm_enabled = val != 0; ++ ++ return 0; ++} ++ ++static int i965_setup_backlight(struct intel_connector *connector, enum pipe unused) ++{ ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ struct intel_panel *panel = &connector->panel; ++ u32 ctl, ctl2; ++ ++ ctl2 = intel_de_read(dev_priv, BLC_PWM_CTL2); ++ panel->backlight.combination_mode = ctl2 & BLM_COMBINATION_MODE; ++ panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965; ++ ++ ctl = intel_de_read(dev_priv, BLC_PWM_CTL); ++ panel->backlight.pwm_level_max = ctl >> 16; ++ ++ if (!panel->backlight.pwm_level_max) ++ panel->backlight.pwm_level_max = get_backlight_max_vbt(connector); ++ ++ if (!panel->backlight.pwm_level_max) ++ return -ENODEV; ++ ++ if (panel->backlight.combination_mode) ++ panel->backlight.pwm_level_max *= 0xff; ++ ++ panel->backlight.pwm_level_min = get_backlight_min_vbt(connector); ++ ++ panel->backlight.pwm_enabled = ctl2 & BLM_PWM_ENABLE; ++ ++ return 0; ++} ++ ++static int vlv_setup_backlight(struct intel_connector *connector, enum pipe pipe) ++{ ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ struct intel_panel *panel = &connector->panel; ++ u32 ctl, ctl2; ++ ++ if (drm_WARN_ON(&dev_priv->drm, pipe != PIPE_A && pipe != PIPE_B)) ++ return -ENODEV; ++ ++ ctl2 = intel_de_read(dev_priv, VLV_BLC_PWM_CTL2(pipe)); ++ panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965; ++ ++ ctl = intel_de_read(dev_priv, VLV_BLC_PWM_CTL(pipe)); ++ panel->backlight.pwm_level_max = ctl >> 16; ++ ++ if (!panel->backlight.pwm_level_max) ++ panel->backlight.pwm_level_max = get_backlight_max_vbt(connector); ++ ++ if (!panel->backlight.pwm_level_max) ++ return -ENODEV; ++ ++ panel->backlight.pwm_level_min = get_backlight_min_vbt(connector); ++ ++ panel->backlight.pwm_enabled = ctl2 & BLM_PWM_ENABLE; ++ ++ return 0; ++} ++ ++static int ++bxt_setup_backlight(struct intel_connector *connector, enum pipe unused) ++{ ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ struct intel_panel *panel = &connector->panel; ++ u32 pwm_ctl, val; ++ ++ panel->backlight.controller = dev_priv->vbt.backlight.controller; ++ ++ pwm_ctl = intel_de_read(dev_priv, ++ BXT_BLC_PWM_CTL(panel->backlight.controller)); ++ ++ /* Controller 1 uses the utility pin. */ ++ if (panel->backlight.controller == 1) { ++ val = intel_de_read(dev_priv, UTIL_PIN_CTL); ++ panel->backlight.util_pin_active_low = ++ val & UTIL_PIN_POLARITY; ++ } ++ ++ panel->backlight.active_low_pwm = pwm_ctl & BXT_BLC_PWM_POLARITY; ++ panel->backlight.pwm_level_max = ++ intel_de_read(dev_priv, BXT_BLC_PWM_FREQ(panel->backlight.controller)); ++ ++ if (!panel->backlight.pwm_level_max) ++ panel->backlight.pwm_level_max = get_backlight_max_vbt(connector); ++ ++ if (!panel->backlight.pwm_level_max) ++ return -ENODEV; ++ ++ panel->backlight.pwm_level_min = get_backlight_min_vbt(connector); ++ ++ panel->backlight.pwm_enabled = pwm_ctl & BXT_BLC_PWM_ENABLE; ++ ++ return 0; ++} ++ ++static int ++cnp_setup_backlight(struct intel_connector *connector, enum pipe unused) ++{ ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ struct intel_panel *panel = &connector->panel; ++ u32 pwm_ctl; ++ ++ /* ++ * CNP has the BXT implementation of backlight, but with only one ++ * controller. TODO: ICP has multiple controllers but we only use ++ * controller 0 for now. ++ */ ++ panel->backlight.controller = 0; ++ ++ pwm_ctl = intel_de_read(dev_priv, ++ BXT_BLC_PWM_CTL(panel->backlight.controller)); ++ ++ panel->backlight.active_low_pwm = pwm_ctl & BXT_BLC_PWM_POLARITY; ++ panel->backlight.pwm_level_max = ++ intel_de_read(dev_priv, BXT_BLC_PWM_FREQ(panel->backlight.controller)); ++ ++ if (!panel->backlight.pwm_level_max) ++ panel->backlight.pwm_level_max = get_backlight_max_vbt(connector); ++ ++ if (!panel->backlight.pwm_level_max) ++ return -ENODEV; ++ ++ panel->backlight.pwm_level_min = get_backlight_min_vbt(connector); ++ ++ panel->backlight.pwm_enabled = pwm_ctl & BXT_BLC_PWM_ENABLE; ++ ++ return 0; ++} ++ ++static int ext_pwm_setup_backlight(struct intel_connector *connector, ++ enum pipe pipe) ++{ ++ struct drm_device *dev = connector->base.dev; ++ struct drm_i915_private *dev_priv = to_i915(dev); ++ struct intel_panel *panel = &connector->panel; ++ const char *desc; ++ u32 level; ++ ++ /* Get the right PWM chip for DSI backlight according to VBT */ ++ if (dev_priv->vbt.dsi.config->pwm_blc == PPS_BLC_PMIC) { ++ panel->backlight.pwm = pwm_get(dev->dev, "pwm_pmic_backlight"); ++ desc = "PMIC"; ++ } else { ++ panel->backlight.pwm = pwm_get(dev->dev, "pwm_soc_backlight"); ++ desc = "SoC"; ++ } ++ ++ if (IS_ERR(panel->backlight.pwm)) { ++ drm_err(&dev_priv->drm, "Failed to get the %s PWM chip\n", ++ desc); ++ panel->backlight.pwm = NULL; ++ return -ENODEV; ++ } ++ ++ panel->backlight.pwm_level_max = 100; /* 100% */ ++ panel->backlight.pwm_level_min = get_backlight_min_vbt(connector); ++ ++ if (pwm_is_enabled(panel->backlight.pwm)) { ++ /* PWM is already enabled, use existing settings */ ++ pwm_get_state(panel->backlight.pwm, &panel->backlight.pwm_state); ++ ++ level = pwm_get_relative_duty_cycle(&panel->backlight.pwm_state, ++ 100); ++ level = intel_panel_invert_pwm_level(connector, level); ++ panel->backlight.pwm_enabled = true; ++ ++ drm_dbg_kms(&dev_priv->drm, "PWM already enabled at freq %ld, VBT freq %d, level %d\n", ++ NSEC_PER_SEC / (unsigned long)panel->backlight.pwm_state.period, ++ get_vbt_pwm_freq(dev_priv), level); ++ } else { ++ /* Set period from VBT frequency, leave other settings at 0. */ ++ panel->backlight.pwm_state.period = ++ NSEC_PER_SEC / get_vbt_pwm_freq(dev_priv); ++ } ++ ++ drm_info(&dev_priv->drm, "Using %s PWM for LCD backlight control\n", ++ desc); ++ return 0; ++} ++ ++static void intel_pwm_set_backlight(const struct drm_connector_state *conn_state, u32 level) ++{ ++ struct intel_connector *connector = to_intel_connector(conn_state->connector); ++ struct intel_panel *panel = &connector->panel; ++ ++ panel->backlight.pwm_funcs->set(conn_state, ++ intel_panel_invert_pwm_level(connector, level)); ++} ++ ++static u32 intel_pwm_get_backlight(struct intel_connector *connector, enum pipe pipe) ++{ ++ struct intel_panel *panel = &connector->panel; ++ ++ return intel_panel_invert_pwm_level(connector, ++ panel->backlight.pwm_funcs->get(connector, pipe)); ++} ++ ++static void intel_pwm_enable_backlight(const struct intel_crtc_state *crtc_state, ++ const struct drm_connector_state *conn_state, u32 level) ++{ ++ struct intel_connector *connector = to_intel_connector(conn_state->connector); ++ struct intel_panel *panel = &connector->panel; ++ ++ panel->backlight.pwm_funcs->enable(crtc_state, conn_state, ++ intel_panel_invert_pwm_level(connector, level)); ++} ++ ++static void intel_pwm_disable_backlight(const struct drm_connector_state *conn_state, u32 level) ++{ ++ struct intel_connector *connector = to_intel_connector(conn_state->connector); ++ struct intel_panel *panel = &connector->panel; ++ ++ panel->backlight.pwm_funcs->disable(conn_state, ++ intel_panel_invert_pwm_level(connector, level)); ++} ++ ++static int intel_pwm_setup_backlight(struct intel_connector *connector, enum pipe pipe) ++{ ++ struct intel_panel *panel = &connector->panel; ++ int ret = panel->backlight.pwm_funcs->setup(connector, pipe); ++ ++ if (ret < 0) ++ return ret; ++ ++ panel->backlight.min = panel->backlight.pwm_level_min; ++ panel->backlight.max = panel->backlight.pwm_level_max; ++ panel->backlight.level = intel_pwm_get_backlight(connector, pipe); ++ panel->backlight.enabled = panel->backlight.pwm_enabled; ++ ++ return 0; ++} ++ ++void intel_panel_update_backlight(struct intel_atomic_state *state, ++ struct intel_encoder *encoder, ++ const struct intel_crtc_state *crtc_state, ++ const struct drm_connector_state *conn_state) ++{ ++ struct intel_connector *connector = to_intel_connector(conn_state->connector); ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ struct intel_panel *panel = &connector->panel; ++ ++ if (!panel->backlight.present) ++ return; ++ ++ mutex_lock(&dev_priv->backlight_lock); ++ if (!panel->backlight.enabled) ++ __intel_panel_enable_backlight(crtc_state, conn_state); ++ ++ mutex_unlock(&dev_priv->backlight_lock); ++} ++ ++int intel_panel_setup_backlight(struct drm_connector *connector, enum pipe pipe) ++{ ++ struct drm_i915_private *dev_priv = to_i915(connector->dev); ++ struct intel_connector *intel_connector = to_intel_connector(connector); ++ struct intel_panel *panel = &intel_connector->panel; ++ int ret; ++ ++ if (!dev_priv->vbt.backlight.present) { ++ if (dev_priv->quirks & QUIRK_BACKLIGHT_PRESENT) { ++ drm_dbg_kms(&dev_priv->drm, ++ "no backlight present per VBT, but present per quirk\n"); ++ } else { ++ drm_dbg_kms(&dev_priv->drm, ++ "no backlight present per VBT\n"); ++ return 0; ++ } ++ } ++ ++ /* ensure intel_panel has been initialized first */ ++ if (drm_WARN_ON(&dev_priv->drm, !panel->backlight.funcs)) ++ return -ENODEV; ++ ++ /* set level and max in panel struct */ ++ mutex_lock(&dev_priv->backlight_lock); ++ ret = panel->backlight.funcs->setup(intel_connector, pipe); ++ mutex_unlock(&dev_priv->backlight_lock); ++ ++ if (ret) { ++ drm_dbg_kms(&dev_priv->drm, ++ "failed to setup backlight for connector %s\n", ++ connector->name); ++ return ret; ++ } ++ ++ panel->backlight.present = true; ++ ++ drm_dbg_kms(&dev_priv->drm, ++ "Connector %s backlight initialized, %s, brightness %u/%u\n", ++ connector->name, ++ enableddisabled(panel->backlight.enabled), ++ panel->backlight.level, panel->backlight.max); ++ ++ return 0; ++} ++ ++void intel_panel_destroy_backlight(struct intel_panel *panel) ++{ ++ /* dispose of the pwm */ ++ if (panel->backlight.pwm) ++ pwm_put(panel->backlight.pwm); ++ ++ panel->backlight.present = false; ++} ++ ++static const struct intel_panel_bl_funcs bxt_pwm_funcs = { ++ .setup = bxt_setup_backlight, ++ .enable = bxt_enable_backlight, ++ .disable = bxt_disable_backlight, ++ .set = bxt_set_backlight, ++ .get = bxt_get_backlight, ++ .hz_to_pwm = bxt_hz_to_pwm, ++}; ++ ++static const struct intel_panel_bl_funcs cnp_pwm_funcs = { ++ .setup = cnp_setup_backlight, ++ .enable = cnp_enable_backlight, ++ .disable = cnp_disable_backlight, ++ .set = bxt_set_backlight, ++ .get = bxt_get_backlight, ++ .hz_to_pwm = cnp_hz_to_pwm, ++}; ++ ++static const struct intel_panel_bl_funcs lpt_pwm_funcs = { ++ .setup = lpt_setup_backlight, ++ .enable = lpt_enable_backlight, ++ .disable = lpt_disable_backlight, ++ .set = lpt_set_backlight, ++ .get = lpt_get_backlight, ++ .hz_to_pwm = lpt_hz_to_pwm, ++}; ++ ++static const struct intel_panel_bl_funcs spt_pwm_funcs = { ++ .setup = lpt_setup_backlight, ++ .enable = lpt_enable_backlight, ++ .disable = lpt_disable_backlight, ++ .set = lpt_set_backlight, ++ .get = lpt_get_backlight, ++ .hz_to_pwm = spt_hz_to_pwm, ++}; ++ ++static const struct intel_panel_bl_funcs pch_pwm_funcs = { ++ .setup = pch_setup_backlight, ++ .enable = pch_enable_backlight, ++ .disable = pch_disable_backlight, ++ .set = pch_set_backlight, ++ .get = pch_get_backlight, ++ .hz_to_pwm = pch_hz_to_pwm, ++}; ++ ++static const struct intel_panel_bl_funcs ext_pwm_funcs = { ++ .setup = ext_pwm_setup_backlight, ++ .enable = ext_pwm_enable_backlight, ++ .disable = ext_pwm_disable_backlight, ++ .set = ext_pwm_set_backlight, ++ .get = ext_pwm_get_backlight, ++}; ++ ++static const struct intel_panel_bl_funcs vlv_pwm_funcs = { ++ .setup = vlv_setup_backlight, ++ .enable = vlv_enable_backlight, ++ .disable = vlv_disable_backlight, ++ .set = vlv_set_backlight, ++ .get = vlv_get_backlight, ++ .hz_to_pwm = vlv_hz_to_pwm, ++}; ++ ++static const struct intel_panel_bl_funcs i965_pwm_funcs = { ++ .setup = i965_setup_backlight, ++ .enable = i965_enable_backlight, ++ .disable = i965_disable_backlight, ++ .set = i9xx_set_backlight, ++ .get = i9xx_get_backlight, ++ .hz_to_pwm = i965_hz_to_pwm, ++}; ++ ++static const struct intel_panel_bl_funcs i9xx_pwm_funcs = { ++ .setup = i9xx_setup_backlight, ++ .enable = i9xx_enable_backlight, ++ .disable = i9xx_disable_backlight, ++ .set = i9xx_set_backlight, ++ .get = i9xx_get_backlight, ++ .hz_to_pwm = i9xx_hz_to_pwm, ++}; ++ ++static const struct intel_panel_bl_funcs pwm_bl_funcs = { ++ .setup = intel_pwm_setup_backlight, ++ .enable = intel_pwm_enable_backlight, ++ .disable = intel_pwm_disable_backlight, ++ .set = intel_pwm_set_backlight, ++ .get = intel_pwm_get_backlight, ++}; ++ ++/* Set up chip specific backlight functions */ ++void ++intel_panel_init_backlight_funcs(struct intel_panel *panel) ++{ ++ struct intel_connector *connector = ++ container_of(panel, struct intel_connector, panel); ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ ++ if (connector->base.connector_type == DRM_MODE_CONNECTOR_DSI && ++ intel_dsi_dcs_init_backlight_funcs(connector) == 0) ++ return; ++ ++ if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) { ++ panel->backlight.pwm_funcs = &bxt_pwm_funcs; ++ } else if (INTEL_PCH_TYPE(dev_priv) >= PCH_CNP) { ++ panel->backlight.pwm_funcs = &cnp_pwm_funcs; ++ } else if (INTEL_PCH_TYPE(dev_priv) >= PCH_LPT) { ++ if (HAS_PCH_LPT(dev_priv)) ++ panel->backlight.pwm_funcs = &lpt_pwm_funcs; ++ else ++ panel->backlight.pwm_funcs = &spt_pwm_funcs; ++ } else if (HAS_PCH_SPLIT(dev_priv)) { ++ panel->backlight.pwm_funcs = &pch_pwm_funcs; ++ } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { ++ if (connector->base.connector_type == DRM_MODE_CONNECTOR_DSI) { ++ panel->backlight.pwm_funcs = &ext_pwm_funcs; ++ } else { ++ panel->backlight.pwm_funcs = &vlv_pwm_funcs; ++ } ++ } else if (DISPLAY_VER(dev_priv) == 4) { ++ panel->backlight.pwm_funcs = &i965_pwm_funcs; ++ } else { ++ panel->backlight.pwm_funcs = &i9xx_pwm_funcs; ++ } ++ ++ if (connector->base.connector_type == DRM_MODE_CONNECTOR_eDP && ++ intel_dp_aux_init_backlight_funcs(connector) == 0) ++ return; ++ ++ /* We're using a standard PWM backlight interface */ ++ panel->backlight.funcs = &pwm_bl_funcs; ++} +diff --git a/drivers/gpu/drm/i915/display/intel_backlight.h b/drivers/gpu/drm/i915/display/intel_backlight.h +new file mode 100644 +index 0000000000000..282020cb47d5b +--- /dev/null ++++ b/drivers/gpu/drm/i915/display/intel_backlight.h +@@ -0,0 +1,51 @@ ++/* SPDX-License-Identifier: MIT */ ++/* ++ * Copyright © 2021 Intel Corporation ++ */ ++ ++#ifndef __INTEL_BACKLIGHT_H__ ++#define __INTEL_BACKLIGHT_H__ ++ ++#include <linux/types.h> ++ ++struct drm_connector; ++struct drm_connector_state; ++struct intel_atomic_state; ++struct intel_connector; ++struct intel_crtc_state; ++struct intel_encoder; ++struct intel_panel; ++enum pipe; ++ ++void intel_panel_init_backlight_funcs(struct intel_panel *panel); ++void intel_panel_destroy_backlight(struct intel_panel *panel); ++void intel_panel_set_backlight_acpi(const struct drm_connector_state *conn_state, ++ u32 level, u32 max); ++int intel_panel_setup_backlight(struct drm_connector *connector, ++ enum pipe pipe); ++void intel_panel_enable_backlight(const struct intel_crtc_state *crtc_state, ++ const struct drm_connector_state *conn_state); ++void intel_panel_update_backlight(struct intel_atomic_state *state, ++ struct intel_encoder *encoder, ++ const struct intel_crtc_state *crtc_state, ++ const struct drm_connector_state *conn_state); ++void intel_panel_disable_backlight(const struct drm_connector_state *old_conn_state); ++void intel_panel_set_pwm_level(const struct drm_connector_state *conn_state, u32 level); ++u32 intel_panel_invert_pwm_level(struct intel_connector *connector, u32 level); ++u32 intel_panel_backlight_level_to_pwm(struct intel_connector *connector, u32 level); ++u32 intel_panel_backlight_level_from_pwm(struct intel_connector *connector, u32 val); ++ ++#if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE) ++int intel_backlight_device_register(struct intel_connector *connector); ++void intel_backlight_device_unregister(struct intel_connector *connector); ++#else /* CONFIG_BACKLIGHT_CLASS_DEVICE */ ++static inline int intel_backlight_device_register(struct intel_connector *connector) ++{ ++ return 0; ++} ++static inline void intel_backlight_device_unregister(struct intel_connector *connector) ++{ ++} ++#endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */ ++ ++#endif /* __INTEL_BACKLIGHT_H__ */ +diff --git a/drivers/gpu/drm/i915/display/intel_connector.c b/drivers/gpu/drm/i915/display/intel_connector.c +index 9bed1ccecea0d..4f49d782eca23 100644 +--- a/drivers/gpu/drm/i915/display/intel_connector.c ++++ b/drivers/gpu/drm/i915/display/intel_connector.c +@@ -29,13 +29,13 @@ + #include <drm/drm_atomic_helper.h> + #include <drm/drm_edid.h> + +-#include "display/intel_panel.h" +- + #include "i915_drv.h" ++#include "intel_backlight.h" + #include "intel_connector.h" + #include "intel_display_debugfs.h" + #include "intel_display_types.h" + #include "intel_hdcp.h" ++#include "intel_panel.h" + + int intel_connector_init(struct intel_connector *connector) + { +diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c +index f61901e26409e..68489c7298302 100644 +--- a/drivers/gpu/drm/i915/display/intel_ddi.c ++++ b/drivers/gpu/drm/i915/display/intel_ddi.c +@@ -29,6 +29,7 @@ + + #include "i915_drv.h" + #include "intel_audio.h" ++#include "intel_backlight.h" + #include "intel_combo_phy.h" + #include "intel_connector.h" + #include "intel_crtc.h" +@@ -49,7 +50,6 @@ + #include "intel_hdmi.h" + #include "intel_hotplug.h" + #include "intel_lspcon.h" +-#include "intel_panel.h" + #include "intel_pps.h" + #include "intel_psr.h" + #include "intel_snps_phy.h" +diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c +index 631cf7d4323c8..f87e4d510ea5e 100644 +--- a/drivers/gpu/drm/i915/display/intel_dp.c ++++ b/drivers/gpu/drm/i915/display/intel_dp.c +@@ -45,6 +45,7 @@ + #include "i915_drv.h" + #include "intel_atomic.h" + #include "intel_audio.h" ++#include "intel_backlight.h" + #include "intel_connector.h" + #include "intel_ddi.h" + #include "intel_de.h" +diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c +index e7b90863aa43d..0a77f0e48aa11 100644 +--- a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c ++++ b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c +@@ -34,10 +34,10 @@ + * for some reason. + */ + ++#include "intel_backlight.h" + #include "intel_display_types.h" + #include "intel_dp.h" + #include "intel_dp_aux_backlight.h" +-#include "intel_panel.h" + + /* TODO: + * Implement HDR, right now we just implement the bare minimum to bring us back into SDR mode so we +diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c +index e0381b0fce914..8f5741ebd58dd 100644 +--- a/drivers/gpu/drm/i915/display/intel_lvds.c ++++ b/drivers/gpu/drm/i915/display/intel_lvds.c +@@ -40,6 +40,7 @@ + + #include "i915_drv.h" + #include "intel_atomic.h" ++#include "intel_backlight.h" + #include "intel_connector.h" + #include "intel_de.h" + #include "intel_display_types.h" +diff --git a/drivers/gpu/drm/i915/display/intel_opregion.c b/drivers/gpu/drm/i915/display/intel_opregion.c +index f7f49b69830fa..aad5c1cd3898e 100644 +--- a/drivers/gpu/drm/i915/display/intel_opregion.c ++++ b/drivers/gpu/drm/i915/display/intel_opregion.c +@@ -30,10 +30,9 @@ + #include <linux/firmware.h> + #include <acpi/video.h> + +-#include "display/intel_panel.h" +- + #include "i915_drv.h" + #include "intel_acpi.h" ++#include "intel_backlight.h" + #include "intel_display_types.h" + #include "intel_opregion.h" + +diff --git a/drivers/gpu/drm/i915/display/intel_panel.c b/drivers/gpu/drm/i915/display/intel_panel.c +index 7d7a60b4d2de7..ad54767440c15 100644 +--- a/drivers/gpu/drm/i915/display/intel_panel.c ++++ b/drivers/gpu/drm/i915/display/intel_panel.c +@@ -28,17 +28,13 @@ + * Chris Wilson <chris@chris-wilson.co.uk> + */ + +-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +- + #include <linux/kernel.h> +-#include <linux/moduleparam.h> + #include <linux/pwm.h> + ++#include "intel_backlight.h" + #include "intel_connector.h" + #include "intel_de.h" + #include "intel_display_types.h" +-#include "intel_dp_aux_backlight.h" +-#include "intel_dsi_dcs_backlight.h" + #include "intel_panel.h" + + void +@@ -456,1767 +452,6 @@ out: + return 0; + } + +-/** +- * scale - scale values from one range to another +- * @source_val: value in range [@source_min..@source_max] +- * @source_min: minimum legal value for @source_val +- * @source_max: maximum legal value for @source_val +- * @target_min: corresponding target value for @source_min +- * @target_max: corresponding target value for @source_max +- * +- * Return @source_val in range [@source_min..@source_max] scaled to range +- * [@target_min..@target_max]. +- */ +-static u32 scale(u32 source_val, +- u32 source_min, u32 source_max, +- u32 target_min, u32 target_max) +-{ +- u64 target_val; +- +- WARN_ON(source_min > source_max); +- WARN_ON(target_min > target_max); +- +- /* defensive */ +- source_val = clamp(source_val, source_min, source_max); +- +- /* avoid overflows */ +- target_val = mul_u32_u32(source_val - source_min, +- target_max - target_min); +- target_val = DIV_ROUND_CLOSEST_ULL(target_val, source_max - source_min); +- target_val += target_min; +- +- return target_val; +-} +- +-/* Scale user_level in range [0..user_max] to [0..hw_max], clamping the result +- * to [hw_min..hw_max]. */ +-static u32 clamp_user_to_hw(struct intel_connector *connector, +- u32 user_level, u32 user_max) +-{ +- struct intel_panel *panel = &connector->panel; +- u32 hw_level; +- +- hw_level = scale(user_level, 0, user_max, 0, panel->backlight.max); +- hw_level = clamp(hw_level, panel->backlight.min, panel->backlight.max); +- +- return hw_level; +-} +- +-/* Scale hw_level in range [hw_min..hw_max] to [0..user_max]. */ +-static u32 scale_hw_to_user(struct intel_connector *connector, +- u32 hw_level, u32 user_max) +-{ +- struct intel_panel *panel = &connector->panel; +- +- return scale(hw_level, panel->backlight.min, panel->backlight.max, +- 0, user_max); +-} +- +-u32 intel_panel_invert_pwm_level(struct intel_connector *connector, u32 val) +-{ +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- struct intel_panel *panel = &connector->panel; +- +- drm_WARN_ON(&dev_priv->drm, panel->backlight.pwm_level_max == 0); +- +- if (dev_priv->params.invert_brightness < 0) +- return val; +- +- if (dev_priv->params.invert_brightness > 0 || +- dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) { +- return panel->backlight.pwm_level_max - val + panel->backlight.pwm_level_min; +- } +- +- return val; +-} +- +-void intel_panel_set_pwm_level(const struct drm_connector_state *conn_state, u32 val) +-{ +- struct intel_connector *connector = to_intel_connector(conn_state->connector); +- struct drm_i915_private *i915 = to_i915(connector->base.dev); +- struct intel_panel *panel = &connector->panel; +- +- drm_dbg_kms(&i915->drm, "set backlight PWM = %d\n", val); +- panel->backlight.pwm_funcs->set(conn_state, val); +-} +- +-u32 intel_panel_backlight_level_to_pwm(struct intel_connector *connector, u32 val) +-{ +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- struct intel_panel *panel = &connector->panel; +- +- drm_WARN_ON_ONCE(&dev_priv->drm, +- panel->backlight.max == 0 || panel->backlight.pwm_level_max == 0); +- +- val = scale(val, panel->backlight.min, panel->backlight.max, +- panel->backlight.pwm_level_min, panel->backlight.pwm_level_max); +- +- return intel_panel_invert_pwm_level(connector, val); +-} +- +-u32 intel_panel_backlight_level_from_pwm(struct intel_connector *connector, u32 val) +-{ +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- struct intel_panel *panel = &connector->panel; +- +- drm_WARN_ON_ONCE(&dev_priv->drm, +- panel->backlight.max == 0 || panel->backlight.pwm_level_max == 0); +- +- if (dev_priv->params.invert_brightness > 0 || +- (dev_priv->params.invert_brightness == 0 && dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS)) +- val = panel->backlight.pwm_level_max - (val - panel->backlight.pwm_level_min); +- +- return scale(val, panel->backlight.pwm_level_min, panel->backlight.pwm_level_max, +- panel->backlight.min, panel->backlight.max); +-} +- +-static u32 lpt_get_backlight(struct intel_connector *connector, enum pipe unused) +-{ +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- +- return intel_de_read(dev_priv, BLC_PWM_PCH_CTL2) & BACKLIGHT_DUTY_CYCLE_MASK; +-} +- +-static u32 pch_get_backlight(struct intel_connector *connector, enum pipe unused) +-{ +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- +- return intel_de_read(dev_priv, BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; +-} +- +-static u32 i9xx_get_backlight(struct intel_connector *connector, enum pipe unused) +-{ +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- struct intel_panel *panel = &connector->panel; +- u32 val; +- +- val = intel_de_read(dev_priv, BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; +- if (DISPLAY_VER(dev_priv) < 4) +- val >>= 1; +- +- if (panel->backlight.combination_mode) { +- u8 lbpc; +- +- pci_read_config_byte(to_pci_dev(dev_priv->drm.dev), LBPC, &lbpc); +- val *= lbpc; +- } +- +- return val; +-} +- +-static u32 vlv_get_backlight(struct intel_connector *connector, enum pipe pipe) +-{ +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- +- if (drm_WARN_ON(&dev_priv->drm, pipe != PIPE_A && pipe != PIPE_B)) +- return 0; +- +- return intel_de_read(dev_priv, VLV_BLC_PWM_CTL(pipe)) & BACKLIGHT_DUTY_CYCLE_MASK; +-} +- +-static u32 bxt_get_backlight(struct intel_connector *connector, enum pipe unused) +-{ +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- struct intel_panel *panel = &connector->panel; +- +- return intel_de_read(dev_priv, +- BXT_BLC_PWM_DUTY(panel->backlight.controller)); +-} +- +-static u32 ext_pwm_get_backlight(struct intel_connector *connector, enum pipe unused) +-{ +- struct intel_panel *panel = &connector->panel; +- struct pwm_state state; +- +- pwm_get_state(panel->backlight.pwm, &state); +- return pwm_get_relative_duty_cycle(&state, 100); +-} +- +-static void lpt_set_backlight(const struct drm_connector_state *conn_state, u32 level) +-{ +- struct intel_connector *connector = to_intel_connector(conn_state->connector); +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- +- u32 val = intel_de_read(dev_priv, BLC_PWM_PCH_CTL2) & ~BACKLIGHT_DUTY_CYCLE_MASK; +- intel_de_write(dev_priv, BLC_PWM_PCH_CTL2, val | level); +-} +- +-static void pch_set_backlight(const struct drm_connector_state *conn_state, u32 level) +-{ +- struct intel_connector *connector = to_intel_connector(conn_state->connector); +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- u32 tmp; +- +- tmp = intel_de_read(dev_priv, BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK; +- intel_de_write(dev_priv, BLC_PWM_CPU_CTL, tmp | level); +-} +- +-static void i9xx_set_backlight(const struct drm_connector_state *conn_state, u32 level) +-{ +- struct intel_connector *connector = to_intel_connector(conn_state->connector); +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- struct intel_panel *panel = &connector->panel; +- u32 tmp, mask; +- +- drm_WARN_ON(&dev_priv->drm, panel->backlight.pwm_level_max == 0); +- +- if (panel->backlight.combination_mode) { +- u8 lbpc; +- +- lbpc = level * 0xfe / panel->backlight.pwm_level_max + 1; +- level /= lbpc; +- pci_write_config_byte(to_pci_dev(dev_priv->drm.dev), LBPC, lbpc); +- } +- +- if (DISPLAY_VER(dev_priv) == 4) { +- mask = BACKLIGHT_DUTY_CYCLE_MASK; +- } else { +- level <<= 1; +- mask = BACKLIGHT_DUTY_CYCLE_MASK_PNV; +- } +- +- tmp = intel_de_read(dev_priv, BLC_PWM_CTL) & ~mask; +- intel_de_write(dev_priv, BLC_PWM_CTL, tmp | level); +-} +- +-static void vlv_set_backlight(const struct drm_connector_state *conn_state, u32 level) +-{ +- struct intel_connector *connector = to_intel_connector(conn_state->connector); +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- enum pipe pipe = to_intel_crtc(conn_state->crtc)->pipe; +- u32 tmp; +- +- tmp = intel_de_read(dev_priv, VLV_BLC_PWM_CTL(pipe)) & ~BACKLIGHT_DUTY_CYCLE_MASK; +- intel_de_write(dev_priv, VLV_BLC_PWM_CTL(pipe), tmp | level); +-} +- +-static void bxt_set_backlight(const struct drm_connector_state *conn_state, u32 level) +-{ +- struct intel_connector *connector = to_intel_connector(conn_state->connector); +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- struct intel_panel *panel = &connector->panel; +- +- intel_de_write(dev_priv, +- BXT_BLC_PWM_DUTY(panel->backlight.controller), level); +-} +- +-static void ext_pwm_set_backlight(const struct drm_connector_state *conn_state, u32 level) +-{ +- struct intel_panel *panel = &to_intel_connector(conn_state->connector)->panel; +- +- pwm_set_relative_duty_cycle(&panel->backlight.pwm_state, level, 100); +- pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state); +-} +- +-static void +-intel_panel_actually_set_backlight(const struct drm_connector_state *conn_state, u32 level) +-{ +- struct intel_connector *connector = to_intel_connector(conn_state->connector); +- struct drm_i915_private *i915 = to_i915(connector->base.dev); +- struct intel_panel *panel = &connector->panel; +- +- drm_dbg_kms(&i915->drm, "set backlight level = %d\n", level); +- +- panel->backlight.funcs->set(conn_state, level); +-} +- +-/* set backlight brightness to level in range [0..max], assuming hw min is +- * respected. +- */ +-void intel_panel_set_backlight_acpi(const struct drm_connector_state *conn_state, +- u32 user_level, u32 user_max) +-{ +- struct intel_connector *connector = to_intel_connector(conn_state->connector); +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- struct intel_panel *panel = &connector->panel; +- u32 hw_level; +- +- /* +- * Lack of crtc may occur during driver init because +- * connection_mutex isn't held across the entire backlight +- * setup + modeset readout, and the BIOS can issue the +- * requests at any time. +- */ +- if (!panel->backlight.present || !conn_state->crtc) +- return; +- +- mutex_lock(&dev_priv->backlight_lock); +- +- drm_WARN_ON(&dev_priv->drm, panel->backlight.max == 0); +- +- hw_level = clamp_user_to_hw(connector, user_level, user_max); +- panel->backlight.level = hw_level; +- +- if (panel->backlight.device) +- panel->backlight.device->props.brightness = +- scale_hw_to_user(connector, +- panel->backlight.level, +- panel->backlight.device->props.max_brightness); +- +- if (panel->backlight.enabled) +- intel_panel_actually_set_backlight(conn_state, hw_level); +- +- mutex_unlock(&dev_priv->backlight_lock); +-} +- +-static void lpt_disable_backlight(const struct drm_connector_state *old_conn_state, u32 level) +-{ +- struct intel_connector *connector = to_intel_connector(old_conn_state->connector); +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- u32 tmp; +- +- intel_panel_set_pwm_level(old_conn_state, level); +- +- /* +- * Although we don't support or enable CPU PWM with LPT/SPT based +- * systems, it may have been enabled prior to loading the +- * driver. Disable to avoid warnings on LCPLL disable. +- * +- * This needs rework if we need to add support for CPU PWM on PCH split +- * platforms. +- */ +- tmp = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2); +- if (tmp & BLM_PWM_ENABLE) { +- drm_dbg_kms(&dev_priv->drm, +- "cpu backlight was enabled, disabling\n"); +- intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, +- tmp & ~BLM_PWM_ENABLE); +- } +- +- tmp = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1); +- intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, tmp & ~BLM_PCH_PWM_ENABLE); +-} +- +-static void pch_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val) +-{ +- struct intel_connector *connector = to_intel_connector(old_conn_state->connector); +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- u32 tmp; +- +- intel_panel_set_pwm_level(old_conn_state, val); +- +- tmp = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2); +- intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, tmp & ~BLM_PWM_ENABLE); +- +- tmp = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1); +- intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, tmp & ~BLM_PCH_PWM_ENABLE); +-} +- +-static void i9xx_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val) +-{ +- intel_panel_set_pwm_level(old_conn_state, val); +-} +- +-static void i965_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val) +-{ +- struct drm_i915_private *dev_priv = to_i915(old_conn_state->connector->dev); +- u32 tmp; +- +- intel_panel_set_pwm_level(old_conn_state, val); +- +- tmp = intel_de_read(dev_priv, BLC_PWM_CTL2); +- intel_de_write(dev_priv, BLC_PWM_CTL2, tmp & ~BLM_PWM_ENABLE); +-} +- +-static void vlv_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val) +-{ +- struct intel_connector *connector = to_intel_connector(old_conn_state->connector); +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- enum pipe pipe = to_intel_crtc(old_conn_state->crtc)->pipe; +- u32 tmp; +- +- intel_panel_set_pwm_level(old_conn_state, val); +- +- tmp = intel_de_read(dev_priv, VLV_BLC_PWM_CTL2(pipe)); +- intel_de_write(dev_priv, VLV_BLC_PWM_CTL2(pipe), +- tmp & ~BLM_PWM_ENABLE); +-} +- +-static void bxt_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val) +-{ +- struct intel_connector *connector = to_intel_connector(old_conn_state->connector); +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- struct intel_panel *panel = &connector->panel; +- u32 tmp; +- +- intel_panel_set_pwm_level(old_conn_state, val); +- +- tmp = intel_de_read(dev_priv, +- BXT_BLC_PWM_CTL(panel->backlight.controller)); +- intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller), +- tmp & ~BXT_BLC_PWM_ENABLE); +- +- if (panel->backlight.controller == 1) { +- val = intel_de_read(dev_priv, UTIL_PIN_CTL); +- val &= ~UTIL_PIN_ENABLE; +- intel_de_write(dev_priv, UTIL_PIN_CTL, val); +- } +-} +- +-static void cnp_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val) +-{ +- struct intel_connector *connector = to_intel_connector(old_conn_state->connector); +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- struct intel_panel *panel = &connector->panel; +- u32 tmp; +- +- intel_panel_set_pwm_level(old_conn_state, val); +- +- tmp = intel_de_read(dev_priv, +- BXT_BLC_PWM_CTL(panel->backlight.controller)); +- intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller), +- tmp & ~BXT_BLC_PWM_ENABLE); +-} +- +-static void ext_pwm_disable_backlight(const struct drm_connector_state *old_conn_state, u32 level) +-{ +- struct intel_connector *connector = to_intel_connector(old_conn_state->connector); +- struct intel_panel *panel = &connector->panel; +- +- panel->backlight.pwm_state.enabled = false; +- pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state); +-} +- +-void intel_panel_disable_backlight(const struct drm_connector_state *old_conn_state) +-{ +- struct intel_connector *connector = to_intel_connector(old_conn_state->connector); +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- struct intel_panel *panel = &connector->panel; +- +- if (!panel->backlight.present) +- return; +- +- /* +- * Do not disable backlight on the vga_switcheroo path. When switching +- * away from i915, the other client may depend on i915 to handle the +- * backlight. This will leave the backlight on unnecessarily when +- * another client is not activated. +- */ +- if (dev_priv->drm.switch_power_state == DRM_SWITCH_POWER_CHANGING) { +- drm_dbg_kms(&dev_priv->drm, +- "Skipping backlight disable on vga switch\n"); +- return; +- } +- +- mutex_lock(&dev_priv->backlight_lock); +- +- if (panel->backlight.device) +- panel->backlight.device->props.power = FB_BLANK_POWERDOWN; +- panel->backlight.enabled = false; +- panel->backlight.funcs->disable(old_conn_state, 0); +- +- mutex_unlock(&dev_priv->backlight_lock); +-} +- +-static void lpt_enable_backlight(const struct intel_crtc_state *crtc_state, +- const struct drm_connector_state *conn_state, u32 level) +-{ +- struct intel_connector *connector = to_intel_connector(conn_state->connector); +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- struct intel_panel *panel = &connector->panel; +- u32 pch_ctl1, pch_ctl2, schicken; +- +- pch_ctl1 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1); +- if (pch_ctl1 & BLM_PCH_PWM_ENABLE) { +- drm_dbg_kms(&dev_priv->drm, "pch backlight already enabled\n"); +- pch_ctl1 &= ~BLM_PCH_PWM_ENABLE; +- intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, pch_ctl1); +- } +- +- if (HAS_PCH_LPT(dev_priv)) { +- schicken = intel_de_read(dev_priv, SOUTH_CHICKEN2); +- if (panel->backlight.alternate_pwm_increment) +- schicken |= LPT_PWM_GRANULARITY; +- else +- schicken &= ~LPT_PWM_GRANULARITY; +- intel_de_write(dev_priv, SOUTH_CHICKEN2, schicken); +- } else { +- schicken = intel_de_read(dev_priv, SOUTH_CHICKEN1); +- if (panel->backlight.alternate_pwm_increment) +- schicken |= SPT_PWM_GRANULARITY; +- else +- schicken &= ~SPT_PWM_GRANULARITY; +- intel_de_write(dev_priv, SOUTH_CHICKEN1, schicken); +- } +- +- pch_ctl2 = panel->backlight.pwm_level_max << 16; +- intel_de_write(dev_priv, BLC_PWM_PCH_CTL2, pch_ctl2); +- +- pch_ctl1 = 0; +- if (panel->backlight.active_low_pwm) +- pch_ctl1 |= BLM_PCH_POLARITY; +- +- /* After LPT, override is the default. */ +- if (HAS_PCH_LPT(dev_priv)) +- pch_ctl1 |= BLM_PCH_OVERRIDE_ENABLE; +- +- intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, pch_ctl1); +- intel_de_posting_read(dev_priv, BLC_PWM_PCH_CTL1); +- intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, +- pch_ctl1 | BLM_PCH_PWM_ENABLE); +- +- /* This won't stick until the above enable. */ +- intel_panel_set_pwm_level(conn_state, level); +-} +- +-static void pch_enable_backlight(const struct intel_crtc_state *crtc_state, +- const struct drm_connector_state *conn_state, u32 level) +-{ +- struct intel_connector *connector = to_intel_connector(conn_state->connector); +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- struct intel_panel *panel = &connector->panel; +- enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; +- u32 cpu_ctl2, pch_ctl1, pch_ctl2; +- +- cpu_ctl2 = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2); +- if (cpu_ctl2 & BLM_PWM_ENABLE) { +- drm_dbg_kms(&dev_priv->drm, "cpu backlight already enabled\n"); +- cpu_ctl2 &= ~BLM_PWM_ENABLE; +- intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, cpu_ctl2); +- } +- +- pch_ctl1 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1); +- if (pch_ctl1 & BLM_PCH_PWM_ENABLE) { +- drm_dbg_kms(&dev_priv->drm, "pch backlight already enabled\n"); +- pch_ctl1 &= ~BLM_PCH_PWM_ENABLE; +- intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, pch_ctl1); +- } +- +- if (cpu_transcoder == TRANSCODER_EDP) +- cpu_ctl2 = BLM_TRANSCODER_EDP; +- else +- cpu_ctl2 = BLM_PIPE(cpu_transcoder); +- intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, cpu_ctl2); +- intel_de_posting_read(dev_priv, BLC_PWM_CPU_CTL2); +- intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, cpu_ctl2 | BLM_PWM_ENABLE); +- +- /* This won't stick until the above enable. */ +- intel_panel_set_pwm_level(conn_state, level); +- +- pch_ctl2 = panel->backlight.pwm_level_max << 16; +- intel_de_write(dev_priv, BLC_PWM_PCH_CTL2, pch_ctl2); +- +- pch_ctl1 = 0; +- if (panel->backlight.active_low_pwm) +- pch_ctl1 |= BLM_PCH_POLARITY; +- +- intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, pch_ctl1); +- intel_de_posting_read(dev_priv, BLC_PWM_PCH_CTL1); +- intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, +- pch_ctl1 | BLM_PCH_PWM_ENABLE); +-} +- +-static void i9xx_enable_backlight(const struct intel_crtc_state *crtc_state, +- const struct drm_connector_state *conn_state, u32 level) +-{ +- struct intel_connector *connector = to_intel_connector(conn_state->connector); +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- struct intel_panel *panel = &connector->panel; +- u32 ctl, freq; +- +- ctl = intel_de_read(dev_priv, BLC_PWM_CTL); +- if (ctl & BACKLIGHT_DUTY_CYCLE_MASK_PNV) { +- drm_dbg_kms(&dev_priv->drm, "backlight already enabled\n"); +- intel_de_write(dev_priv, BLC_PWM_CTL, 0); +- } +- +- freq = panel->backlight.pwm_level_max; +- if (panel->backlight.combination_mode) +- freq /= 0xff; +- +- ctl = freq << 17; +- if (panel->backlight.combination_mode) +- ctl |= BLM_LEGACY_MODE; +- if (IS_PINEVIEW(dev_priv) && panel->backlight.active_low_pwm) +- ctl |= BLM_POLARITY_PNV; +- +- intel_de_write(dev_priv, BLC_PWM_CTL, ctl); +- intel_de_posting_read(dev_priv, BLC_PWM_CTL); +- +- /* XXX: combine this into above write? */ +- intel_panel_set_pwm_level(conn_state, level); +- +- /* +- * Needed to enable backlight on some 855gm models. BLC_HIST_CTL is +- * 855gm only, but checking for gen2 is safe, as 855gm is the only gen2 +- * that has backlight. +- */ +- if (DISPLAY_VER(dev_priv) == 2) +- intel_de_write(dev_priv, BLC_HIST_CTL, BLM_HISTOGRAM_ENABLE); +-} +- +-static void i965_enable_backlight(const struct intel_crtc_state *crtc_state, +- const struct drm_connector_state *conn_state, u32 level) +-{ +- struct intel_connector *connector = to_intel_connector(conn_state->connector); +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- struct intel_panel *panel = &connector->panel; +- enum pipe pipe = to_intel_crtc(conn_state->crtc)->pipe; +- u32 ctl, ctl2, freq; +- +- ctl2 = intel_de_read(dev_priv, BLC_PWM_CTL2); +- if (ctl2 & BLM_PWM_ENABLE) { +- drm_dbg_kms(&dev_priv->drm, "backlight already enabled\n"); +- ctl2 &= ~BLM_PWM_ENABLE; +- intel_de_write(dev_priv, BLC_PWM_CTL2, ctl2); +- } +- +- freq = panel->backlight.pwm_level_max; +- if (panel->backlight.combination_mode) +- freq /= 0xff; +- +- ctl = freq << 16; +- intel_de_write(dev_priv, BLC_PWM_CTL, ctl); +- +- ctl2 = BLM_PIPE(pipe); +- if (panel->backlight.combination_mode) +- ctl2 |= BLM_COMBINATION_MODE; +- if (panel->backlight.active_low_pwm) +- ctl2 |= BLM_POLARITY_I965; +- intel_de_write(dev_priv, BLC_PWM_CTL2, ctl2); +- intel_de_posting_read(dev_priv, BLC_PWM_CTL2); +- intel_de_write(dev_priv, BLC_PWM_CTL2, ctl2 | BLM_PWM_ENABLE); +- +- intel_panel_set_pwm_level(conn_state, level); +-} +- +-static void vlv_enable_backlight(const struct intel_crtc_state *crtc_state, +- const struct drm_connector_state *conn_state, u32 level) +-{ +- struct intel_connector *connector = to_intel_connector(conn_state->connector); +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- struct intel_panel *panel = &connector->panel; +- enum pipe pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe; +- u32 ctl, ctl2; +- +- ctl2 = intel_de_read(dev_priv, VLV_BLC_PWM_CTL2(pipe)); +- if (ctl2 & BLM_PWM_ENABLE) { +- drm_dbg_kms(&dev_priv->drm, "backlight already enabled\n"); +- ctl2 &= ~BLM_PWM_ENABLE; +- intel_de_write(dev_priv, VLV_BLC_PWM_CTL2(pipe), ctl2); +- } +- +- ctl = panel->backlight.pwm_level_max << 16; +- intel_de_write(dev_priv, VLV_BLC_PWM_CTL(pipe), ctl); +- +- /* XXX: combine this into above write? */ +- intel_panel_set_pwm_level(conn_state, level); +- +- ctl2 = 0; +- if (panel->backlight.active_low_pwm) +- ctl2 |= BLM_POLARITY_I965; +- intel_de_write(dev_priv, VLV_BLC_PWM_CTL2(pipe), ctl2); +- intel_de_posting_read(dev_priv, VLV_BLC_PWM_CTL2(pipe)); +- intel_de_write(dev_priv, VLV_BLC_PWM_CTL2(pipe), +- ctl2 | BLM_PWM_ENABLE); +-} +- +-static void bxt_enable_backlight(const struct intel_crtc_state *crtc_state, +- const struct drm_connector_state *conn_state, u32 level) +-{ +- struct intel_connector *connector = to_intel_connector(conn_state->connector); +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- struct intel_panel *panel = &connector->panel; +- enum pipe pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe; +- u32 pwm_ctl, val; +- +- /* Controller 1 uses the utility pin. */ +- if (panel->backlight.controller == 1) { +- val = intel_de_read(dev_priv, UTIL_PIN_CTL); +- if (val & UTIL_PIN_ENABLE) { +- drm_dbg_kms(&dev_priv->drm, +- "util pin already enabled\n"); +- val &= ~UTIL_PIN_ENABLE; +- intel_de_write(dev_priv, UTIL_PIN_CTL, val); +- } +- +- val = 0; +- if (panel->backlight.util_pin_active_low) +- val |= UTIL_PIN_POLARITY; +- intel_de_write(dev_priv, UTIL_PIN_CTL, +- val | UTIL_PIN_PIPE(pipe) | UTIL_PIN_MODE_PWM | UTIL_PIN_ENABLE); +- } +- +- pwm_ctl = intel_de_read(dev_priv, +- BXT_BLC_PWM_CTL(panel->backlight.controller)); +- if (pwm_ctl & BXT_BLC_PWM_ENABLE) { +- drm_dbg_kms(&dev_priv->drm, "backlight already enabled\n"); +- pwm_ctl &= ~BXT_BLC_PWM_ENABLE; +- intel_de_write(dev_priv, +- BXT_BLC_PWM_CTL(panel->backlight.controller), +- pwm_ctl); +- } +- +- intel_de_write(dev_priv, +- BXT_BLC_PWM_FREQ(panel->backlight.controller), +- panel->backlight.pwm_level_max); +- +- intel_panel_set_pwm_level(conn_state, level); +- +- pwm_ctl = 0; +- if (panel->backlight.active_low_pwm) +- pwm_ctl |= BXT_BLC_PWM_POLARITY; +- +- intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller), +- pwm_ctl); +- intel_de_posting_read(dev_priv, +- BXT_BLC_PWM_CTL(panel->backlight.controller)); +- intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller), +- pwm_ctl | BXT_BLC_PWM_ENABLE); +-} +- +-static void cnp_enable_backlight(const struct intel_crtc_state *crtc_state, +- const struct drm_connector_state *conn_state, u32 level) +-{ +- struct intel_connector *connector = to_intel_connector(conn_state->connector); +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- struct intel_panel *panel = &connector->panel; +- u32 pwm_ctl; +- +- pwm_ctl = intel_de_read(dev_priv, +- BXT_BLC_PWM_CTL(panel->backlight.controller)); +- if (pwm_ctl & BXT_BLC_PWM_ENABLE) { +- drm_dbg_kms(&dev_priv->drm, "backlight already enabled\n"); +- pwm_ctl &= ~BXT_BLC_PWM_ENABLE; +- intel_de_write(dev_priv, +- BXT_BLC_PWM_CTL(panel->backlight.controller), +- pwm_ctl); +- } +- +- intel_de_write(dev_priv, +- BXT_BLC_PWM_FREQ(panel->backlight.controller), +- panel->backlight.pwm_level_max); +- +- intel_panel_set_pwm_level(conn_state, level); +- +- pwm_ctl = 0; +- if (panel->backlight.active_low_pwm) +- pwm_ctl |= BXT_BLC_PWM_POLARITY; +- +- intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller), +- pwm_ctl); +- intel_de_posting_read(dev_priv, +- BXT_BLC_PWM_CTL(panel->backlight.controller)); +- intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller), +- pwm_ctl | BXT_BLC_PWM_ENABLE); +-} +- +-static void ext_pwm_enable_backlight(const struct intel_crtc_state *crtc_state, +- const struct drm_connector_state *conn_state, u32 level) +-{ +- struct intel_connector *connector = to_intel_connector(conn_state->connector); +- struct intel_panel *panel = &connector->panel; +- +- pwm_set_relative_duty_cycle(&panel->backlight.pwm_state, level, 100); +- panel->backlight.pwm_state.enabled = true; +- pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state); +-} +- +-static void __intel_panel_enable_backlight(const struct intel_crtc_state *crtc_state, +- const struct drm_connector_state *conn_state) +-{ +- struct intel_connector *connector = to_intel_connector(conn_state->connector); +- struct intel_panel *panel = &connector->panel; +- +- WARN_ON(panel->backlight.max == 0); +- +- if (panel->backlight.level <= panel->backlight.min) { +- panel->backlight.level = panel->backlight.max; +- if (panel->backlight.device) +- panel->backlight.device->props.brightness = +- scale_hw_to_user(connector, +- panel->backlight.level, +- panel->backlight.device->props.max_brightness); +- } +- +- panel->backlight.funcs->enable(crtc_state, conn_state, panel->backlight.level); +- panel->backlight.enabled = true; +- if (panel->backlight.device) +- panel->backlight.device->props.power = FB_BLANK_UNBLANK; +-} +- +-void intel_panel_enable_backlight(const struct intel_crtc_state *crtc_state, +- const struct drm_connector_state *conn_state) +-{ +- struct intel_connector *connector = to_intel_connector(conn_state->connector); +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- struct intel_panel *panel = &connector->panel; +- enum pipe pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe; +- +- if (!panel->backlight.present) +- return; +- +- drm_dbg_kms(&dev_priv->drm, "pipe %c\n", pipe_name(pipe)); +- +- mutex_lock(&dev_priv->backlight_lock); +- +- __intel_panel_enable_backlight(crtc_state, conn_state); +- +- mutex_unlock(&dev_priv->backlight_lock); +-} +- +-#if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE) +-static u32 intel_panel_get_backlight(struct intel_connector *connector) +-{ +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- struct intel_panel *panel = &connector->panel; +- u32 val = 0; +- +- mutex_lock(&dev_priv->backlight_lock); +- +- if (panel->backlight.enabled) +- val = panel->backlight.funcs->get(connector, intel_connector_get_pipe(connector)); +- +- mutex_unlock(&dev_priv->backlight_lock); +- +- drm_dbg_kms(&dev_priv->drm, "get backlight PWM = %d\n", val); +- return val; +-} +- +-/* Scale user_level in range [0..user_max] to [hw_min..hw_max]. */ +-static u32 scale_user_to_hw(struct intel_connector *connector, +- u32 user_level, u32 user_max) +-{ +- struct intel_panel *panel = &connector->panel; +- +- return scale(user_level, 0, user_max, +- panel->backlight.min, panel->backlight.max); +-} +- +-/* set backlight brightness to level in range [0..max], scaling wrt hw min */ +-static void intel_panel_set_backlight(const struct drm_connector_state *conn_state, +- u32 user_level, u32 user_max) +-{ +- struct intel_connector *connector = to_intel_connector(conn_state->connector); +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- struct intel_panel *panel = &connector->panel; +- u32 hw_level; +- +- if (!panel->backlight.present) +- return; +- +- mutex_lock(&dev_priv->backlight_lock); +- +- drm_WARN_ON(&dev_priv->drm, panel->backlight.max == 0); +- +- hw_level = scale_user_to_hw(connector, user_level, user_max); +- panel->backlight.level = hw_level; +- +- if (panel->backlight.enabled) +- intel_panel_actually_set_backlight(conn_state, hw_level); +- +- mutex_unlock(&dev_priv->backlight_lock); +-} +- +-static int intel_backlight_device_update_status(struct backlight_device *bd) +-{ +- struct intel_connector *connector = bl_get_data(bd); +- struct intel_panel *panel = &connector->panel; +- struct drm_device *dev = connector->base.dev; +- +- drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); +- DRM_DEBUG_KMS("updating intel_backlight, brightness=%d/%d\n", +- bd->props.brightness, bd->props.max_brightness); +- intel_panel_set_backlight(connector->base.state, bd->props.brightness, +- bd->props.max_brightness); +- +- /* +- * Allow flipping bl_power as a sub-state of enabled. Sadly the +- * backlight class device does not make it easy to to differentiate +- * between callbacks for brightness and bl_power, so our backlight_power +- * callback needs to take this into account. +- */ +- if (panel->backlight.enabled) { +- if (panel->backlight.power) { +- bool enable = bd->props.power == FB_BLANK_UNBLANK && +- bd->props.brightness != 0; +- panel->backlight.power(connector, enable); +- } +- } else { +- bd->props.power = FB_BLANK_POWERDOWN; +- } +- +- drm_modeset_unlock(&dev->mode_config.connection_mutex); +- return 0; +-} +- +-static int intel_backlight_device_get_brightness(struct backlight_device *bd) +-{ +- struct intel_connector *connector = bl_get_data(bd); +- struct drm_device *dev = connector->base.dev; +- struct drm_i915_private *dev_priv = to_i915(dev); +- intel_wakeref_t wakeref; +- int ret = 0; +- +- with_intel_runtime_pm(&dev_priv->runtime_pm, wakeref) { +- u32 hw_level; +- +- drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); +- +- hw_level = intel_panel_get_backlight(connector); +- ret = scale_hw_to_user(connector, +- hw_level, bd->props.max_brightness); +- +- drm_modeset_unlock(&dev->mode_config.connection_mutex); +- } +- +- return ret; +-} +- +-static const struct backlight_ops intel_backlight_device_ops = { +- .update_status = intel_backlight_device_update_status, +- .get_brightness = intel_backlight_device_get_brightness, +-}; +- +-int intel_backlight_device_register(struct intel_connector *connector) +-{ +- struct drm_i915_private *i915 = to_i915(connector->base.dev); +- struct intel_panel *panel = &connector->panel; +- struct backlight_properties props; +- struct backlight_device *bd; +- const char *name; +- int ret = 0; +- +- if (WARN_ON(panel->backlight.device)) +- return -ENODEV; +- +- if (!panel->backlight.present) +- return 0; +- +- WARN_ON(panel->backlight.max == 0); +- +- memset(&props, 0, sizeof(props)); +- props.type = BACKLIGHT_RAW; +- +- /* +- * Note: Everything should work even if the backlight device max +- * presented to the userspace is arbitrarily chosen. +- */ +- props.max_brightness = panel->backlight.max; +- props.brightness = scale_hw_to_user(connector, +- panel->backlight.level, +- props.max_brightness); +- +- if (panel->backlight.enabled) +- props.power = FB_BLANK_UNBLANK; +- else +- props.power = FB_BLANK_POWERDOWN; +- +- name = kstrdup("intel_backlight", GFP_KERNEL); +- if (!name) +- return -ENOMEM; +- +- bd = backlight_device_register(name, connector->base.kdev, connector, +- &intel_backlight_device_ops, &props); +- +- /* +- * Using the same name independent of the drm device or connector +- * prevents registration of multiple backlight devices in the +- * driver. However, we need to use the default name for backward +- * compatibility. Use unique names for subsequent backlight devices as a +- * fallback when the default name already exists. +- */ +- if (IS_ERR(bd) && PTR_ERR(bd) == -EEXIST) { +- kfree(name); +- name = kasprintf(GFP_KERNEL, "card%d-%s-backlight", +- i915->drm.primary->index, connector->base.name); +- if (!name) +- return -ENOMEM; +- +- bd = backlight_device_register(name, connector->base.kdev, connector, +- &intel_backlight_device_ops, &props); +- } +- +- if (IS_ERR(bd)) { +- drm_err(&i915->drm, +- "[CONNECTOR:%d:%s] backlight device %s register failed: %ld\n", +- connector->base.base.id, connector->base.name, name, PTR_ERR(bd)); +- ret = PTR_ERR(bd); +- goto out; +- } +- +- panel->backlight.device = bd; +- +- drm_dbg_kms(&i915->drm, +- "[CONNECTOR:%d:%s] backlight device %s registered\n", +- connector->base.base.id, connector->base.name, name); +- +-out: +- kfree(name); +- +- return ret; +-} +- +-void intel_backlight_device_unregister(struct intel_connector *connector) +-{ +- struct intel_panel *panel = &connector->panel; +- +- if (panel->backlight.device) { +- backlight_device_unregister(panel->backlight.device); +- panel->backlight.device = NULL; +- } +-} +-#endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */ +- +-/* +- * CNP: PWM clock frequency is 19.2 MHz or 24 MHz. +- * PWM increment = 1 +- */ +-static u32 cnp_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz) +-{ +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- +- return DIV_ROUND_CLOSEST(KHz(RUNTIME_INFO(dev_priv)->rawclk_freq), +- pwm_freq_hz); +-} +- +-/* +- * BXT: PWM clock frequency = 19.2 MHz. +- */ +-static u32 bxt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz) +-{ +- return DIV_ROUND_CLOSEST(KHz(19200), pwm_freq_hz); +-} +- +-/* +- * SPT: This value represents the period of the PWM stream in clock periods +- * multiplied by 16 (default increment) or 128 (alternate increment selected in +- * SCHICKEN_1 bit 0). PWM clock is 24 MHz. +- */ +-static u32 spt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz) +-{ +- struct intel_panel *panel = &connector->panel; +- u32 mul; +- +- if (panel->backlight.alternate_pwm_increment) +- mul = 128; +- else +- mul = 16; +- +- return DIV_ROUND_CLOSEST(MHz(24), pwm_freq_hz * mul); +-} +- +-/* +- * LPT: This value represents the period of the PWM stream in clock periods +- * multiplied by 128 (default increment) or 16 (alternate increment, selected in +- * LPT SOUTH_CHICKEN2 register bit 5). +- */ +-static u32 lpt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz) +-{ +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- struct intel_panel *panel = &connector->panel; +- u32 mul, clock; +- +- if (panel->backlight.alternate_pwm_increment) +- mul = 16; +- else +- mul = 128; +- +- if (HAS_PCH_LPT_H(dev_priv)) +- clock = MHz(135); /* LPT:H */ +- else +- clock = MHz(24); /* LPT:LP */ +- +- return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * mul); +-} +- +-/* +- * ILK/SNB/IVB: This value represents the period of the PWM stream in PCH +- * display raw clocks multiplied by 128. +- */ +-static u32 pch_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz) +-{ +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- +- return DIV_ROUND_CLOSEST(KHz(RUNTIME_INFO(dev_priv)->rawclk_freq), +- pwm_freq_hz * 128); +-} +- +-/* +- * Gen2: This field determines the number of time base events (display core +- * clock frequency/32) in total for a complete cycle of modulated backlight +- * control. +- * +- * Gen3: A time base event equals the display core clock ([DevPNV] HRAW clock) +- * divided by 32. +- */ +-static u32 i9xx_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz) +-{ +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- int clock; +- +- if (IS_PINEVIEW(dev_priv)) +- clock = KHz(RUNTIME_INFO(dev_priv)->rawclk_freq); +- else +- clock = KHz(dev_priv->cdclk.hw.cdclk); +- +- return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * 32); +-} +- +-/* +- * Gen4: This value represents the period of the PWM stream in display core +- * clocks ([DevCTG] HRAW clocks) multiplied by 128. +- * +- */ +-static u32 i965_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz) +-{ +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- int clock; +- +- if (IS_G4X(dev_priv)) +- clock = KHz(RUNTIME_INFO(dev_priv)->rawclk_freq); +- else +- clock = KHz(dev_priv->cdclk.hw.cdclk); +- +- return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * 128); +-} +- +-/* +- * VLV: This value represents the period of the PWM stream in display core +- * clocks ([DevCTG] 200MHz HRAW clocks) multiplied by 128 or 25MHz S0IX clocks +- * multiplied by 16. CHV uses a 19.2MHz S0IX clock. +- */ +-static u32 vlv_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz) +-{ +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- int mul, clock; +- +- if ((intel_de_read(dev_priv, CBR1_VLV) & CBR_PWM_CLOCK_MUX_SELECT) == 0) { +- if (IS_CHERRYVIEW(dev_priv)) +- clock = KHz(19200); +- else +- clock = MHz(25); +- mul = 16; +- } else { +- clock = KHz(RUNTIME_INFO(dev_priv)->rawclk_freq); +- mul = 128; +- } +- +- return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * mul); +-} +- +-static u16 get_vbt_pwm_freq(struct drm_i915_private *dev_priv) +-{ +- u16 pwm_freq_hz = dev_priv->vbt.backlight.pwm_freq_hz; +- +- if (pwm_freq_hz) { +- drm_dbg_kms(&dev_priv->drm, +- "VBT defined backlight frequency %u Hz\n", +- pwm_freq_hz); +- } else { +- pwm_freq_hz = 200; +- drm_dbg_kms(&dev_priv->drm, +- "default backlight frequency %u Hz\n", +- pwm_freq_hz); +- } +- +- return pwm_freq_hz; +-} +- +-static u32 get_backlight_max_vbt(struct intel_connector *connector) +-{ +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- struct intel_panel *panel = &connector->panel; +- u16 pwm_freq_hz = get_vbt_pwm_freq(dev_priv); +- u32 pwm; +- +- if (!panel->backlight.pwm_funcs->hz_to_pwm) { +- drm_dbg_kms(&dev_priv->drm, +- "backlight frequency conversion not supported\n"); +- return 0; +- } +- +- pwm = panel->backlight.pwm_funcs->hz_to_pwm(connector, pwm_freq_hz); +- if (!pwm) { +- drm_dbg_kms(&dev_priv->drm, +- "backlight frequency conversion failed\n"); +- return 0; +- } +- +- return pwm; +-} +- +-/* +- * Note: The setup hooks can't assume pipe is set! +- */ +-static u32 get_backlight_min_vbt(struct intel_connector *connector) +-{ +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- struct intel_panel *panel = &connector->panel; +- int min; +- +- drm_WARN_ON(&dev_priv->drm, panel->backlight.pwm_level_max == 0); +- +- /* +- * XXX: If the vbt value is 255, it makes min equal to max, which leads +- * to problems. There are such machines out there. Either our +- * interpretation is wrong or the vbt has bogus data. Or both. Safeguard +- * against this by letting the minimum be at most (arbitrarily chosen) +- * 25% of the max. +- */ +- min = clamp_t(int, dev_priv->vbt.backlight.min_brightness, 0, 64); +- if (min != dev_priv->vbt.backlight.min_brightness) { +- drm_dbg_kms(&dev_priv->drm, +- "clamping VBT min backlight %d/255 to %d/255\n", +- dev_priv->vbt.backlight.min_brightness, min); +- } +- +- /* vbt value is a coefficient in range [0..255] */ +- return scale(min, 0, 255, 0, panel->backlight.pwm_level_max); +-} +- +-static int lpt_setup_backlight(struct intel_connector *connector, enum pipe unused) +-{ +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- struct intel_panel *panel = &connector->panel; +- u32 cpu_ctl2, pch_ctl1, pch_ctl2, val; +- bool alt, cpu_mode; +- +- if (HAS_PCH_LPT(dev_priv)) +- alt = intel_de_read(dev_priv, SOUTH_CHICKEN2) & LPT_PWM_GRANULARITY; +- else +- alt = intel_de_read(dev_priv, SOUTH_CHICKEN1) & SPT_PWM_GRANULARITY; +- panel->backlight.alternate_pwm_increment = alt; +- +- pch_ctl1 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1); +- panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY; +- +- pch_ctl2 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL2); +- panel->backlight.pwm_level_max = pch_ctl2 >> 16; +- +- cpu_ctl2 = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2); +- +- if (!panel->backlight.pwm_level_max) +- panel->backlight.pwm_level_max = get_backlight_max_vbt(connector); +- +- if (!panel->backlight.pwm_level_max) +- return -ENODEV; +- +- panel->backlight.pwm_level_min = get_backlight_min_vbt(connector); +- +- panel->backlight.pwm_enabled = pch_ctl1 & BLM_PCH_PWM_ENABLE; +- +- cpu_mode = panel->backlight.pwm_enabled && HAS_PCH_LPT(dev_priv) && +- !(pch_ctl1 & BLM_PCH_OVERRIDE_ENABLE) && +- (cpu_ctl2 & BLM_PWM_ENABLE); +- +- if (cpu_mode) { +- val = pch_get_backlight(connector, unused); +- +- drm_dbg_kms(&dev_priv->drm, +- "CPU backlight register was enabled, switching to PCH override\n"); +- +- /* Write converted CPU PWM value to PCH override register */ +- lpt_set_backlight(connector->base.state, val); +- intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, +- pch_ctl1 | BLM_PCH_OVERRIDE_ENABLE); +- +- intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, +- cpu_ctl2 & ~BLM_PWM_ENABLE); +- } +- +- return 0; +-} +- +-static int pch_setup_backlight(struct intel_connector *connector, enum pipe unused) +-{ +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- struct intel_panel *panel = &connector->panel; +- u32 cpu_ctl2, pch_ctl1, pch_ctl2; +- +- pch_ctl1 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1); +- panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY; +- +- pch_ctl2 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL2); +- panel->backlight.pwm_level_max = pch_ctl2 >> 16; +- +- if (!panel->backlight.pwm_level_max) +- panel->backlight.pwm_level_max = get_backlight_max_vbt(connector); +- +- if (!panel->backlight.pwm_level_max) +- return -ENODEV; +- +- panel->backlight.pwm_level_min = get_backlight_min_vbt(connector); +- +- cpu_ctl2 = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2); +- panel->backlight.pwm_enabled = (cpu_ctl2 & BLM_PWM_ENABLE) && +- (pch_ctl1 & BLM_PCH_PWM_ENABLE); +- +- return 0; +-} +- +-static int i9xx_setup_backlight(struct intel_connector *connector, enum pipe unused) +-{ +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- struct intel_panel *panel = &connector->panel; +- u32 ctl, val; +- +- ctl = intel_de_read(dev_priv, BLC_PWM_CTL); +- +- if (DISPLAY_VER(dev_priv) == 2 || IS_I915GM(dev_priv) || IS_I945GM(dev_priv)) +- panel->backlight.combination_mode = ctl & BLM_LEGACY_MODE; +- +- if (IS_PINEVIEW(dev_priv)) +- panel->backlight.active_low_pwm = ctl & BLM_POLARITY_PNV; +- +- panel->backlight.pwm_level_max = ctl >> 17; +- +- if (!panel->backlight.pwm_level_max) { +- panel->backlight.pwm_level_max = get_backlight_max_vbt(connector); +- panel->backlight.pwm_level_max >>= 1; +- } +- +- if (!panel->backlight.pwm_level_max) +- return -ENODEV; +- +- if (panel->backlight.combination_mode) +- panel->backlight.pwm_level_max *= 0xff; +- +- panel->backlight.pwm_level_min = get_backlight_min_vbt(connector); +- +- val = i9xx_get_backlight(connector, unused); +- val = intel_panel_invert_pwm_level(connector, val); +- val = clamp(val, panel->backlight.pwm_level_min, panel->backlight.pwm_level_max); +- +- panel->backlight.pwm_enabled = val != 0; +- +- return 0; +-} +- +-static int i965_setup_backlight(struct intel_connector *connector, enum pipe unused) +-{ +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- struct intel_panel *panel = &connector->panel; +- u32 ctl, ctl2; +- +- ctl2 = intel_de_read(dev_priv, BLC_PWM_CTL2); +- panel->backlight.combination_mode = ctl2 & BLM_COMBINATION_MODE; +- panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965; +- +- ctl = intel_de_read(dev_priv, BLC_PWM_CTL); +- panel->backlight.pwm_level_max = ctl >> 16; +- +- if (!panel->backlight.pwm_level_max) +- panel->backlight.pwm_level_max = get_backlight_max_vbt(connector); +- +- if (!panel->backlight.pwm_level_max) +- return -ENODEV; +- +- if (panel->backlight.combination_mode) +- panel->backlight.pwm_level_max *= 0xff; +- +- panel->backlight.pwm_level_min = get_backlight_min_vbt(connector); +- +- panel->backlight.pwm_enabled = ctl2 & BLM_PWM_ENABLE; +- +- return 0; +-} +- +-static int vlv_setup_backlight(struct intel_connector *connector, enum pipe pipe) +-{ +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- struct intel_panel *panel = &connector->panel; +- u32 ctl, ctl2; +- +- if (drm_WARN_ON(&dev_priv->drm, pipe != PIPE_A && pipe != PIPE_B)) +- return -ENODEV; +- +- ctl2 = intel_de_read(dev_priv, VLV_BLC_PWM_CTL2(pipe)); +- panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965; +- +- ctl = intel_de_read(dev_priv, VLV_BLC_PWM_CTL(pipe)); +- panel->backlight.pwm_level_max = ctl >> 16; +- +- if (!panel->backlight.pwm_level_max) +- panel->backlight.pwm_level_max = get_backlight_max_vbt(connector); +- +- if (!panel->backlight.pwm_level_max) +- return -ENODEV; +- +- panel->backlight.pwm_level_min = get_backlight_min_vbt(connector); +- +- panel->backlight.pwm_enabled = ctl2 & BLM_PWM_ENABLE; +- +- return 0; +-} +- +-static int +-bxt_setup_backlight(struct intel_connector *connector, enum pipe unused) +-{ +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- struct intel_panel *panel = &connector->panel; +- u32 pwm_ctl, val; +- +- panel->backlight.controller = dev_priv->vbt.backlight.controller; +- +- pwm_ctl = intel_de_read(dev_priv, +- BXT_BLC_PWM_CTL(panel->backlight.controller)); +- +- /* Controller 1 uses the utility pin. */ +- if (panel->backlight.controller == 1) { +- val = intel_de_read(dev_priv, UTIL_PIN_CTL); +- panel->backlight.util_pin_active_low = +- val & UTIL_PIN_POLARITY; +- } +- +- panel->backlight.active_low_pwm = pwm_ctl & BXT_BLC_PWM_POLARITY; +- panel->backlight.pwm_level_max = +- intel_de_read(dev_priv, BXT_BLC_PWM_FREQ(panel->backlight.controller)); +- +- if (!panel->backlight.pwm_level_max) +- panel->backlight.pwm_level_max = get_backlight_max_vbt(connector); +- +- if (!panel->backlight.pwm_level_max) +- return -ENODEV; +- +- panel->backlight.pwm_level_min = get_backlight_min_vbt(connector); +- +- panel->backlight.pwm_enabled = pwm_ctl & BXT_BLC_PWM_ENABLE; +- +- return 0; +-} +- +-static int +-cnp_setup_backlight(struct intel_connector *connector, enum pipe unused) +-{ +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- struct intel_panel *panel = &connector->panel; +- u32 pwm_ctl; +- +- /* +- * CNP has the BXT implementation of backlight, but with only one +- * controller. TODO: ICP has multiple controllers but we only use +- * controller 0 for now. +- */ +- panel->backlight.controller = 0; +- +- pwm_ctl = intel_de_read(dev_priv, +- BXT_BLC_PWM_CTL(panel->backlight.controller)); +- +- panel->backlight.active_low_pwm = pwm_ctl & BXT_BLC_PWM_POLARITY; +- panel->backlight.pwm_level_max = +- intel_de_read(dev_priv, BXT_BLC_PWM_FREQ(panel->backlight.controller)); +- +- if (!panel->backlight.pwm_level_max) +- panel->backlight.pwm_level_max = get_backlight_max_vbt(connector); +- +- if (!panel->backlight.pwm_level_max) +- return -ENODEV; +- +- panel->backlight.pwm_level_min = get_backlight_min_vbt(connector); +- +- panel->backlight.pwm_enabled = pwm_ctl & BXT_BLC_PWM_ENABLE; +- +- return 0; +-} +- +-static int ext_pwm_setup_backlight(struct intel_connector *connector, +- enum pipe pipe) +-{ +- struct drm_device *dev = connector->base.dev; +- struct drm_i915_private *dev_priv = to_i915(dev); +- struct intel_panel *panel = &connector->panel; +- const char *desc; +- u32 level; +- +- /* Get the right PWM chip for DSI backlight according to VBT */ +- if (dev_priv->vbt.dsi.config->pwm_blc == PPS_BLC_PMIC) { +- panel->backlight.pwm = pwm_get(dev->dev, "pwm_pmic_backlight"); +- desc = "PMIC"; +- } else { +- panel->backlight.pwm = pwm_get(dev->dev, "pwm_soc_backlight"); +- desc = "SoC"; +- } +- +- if (IS_ERR(panel->backlight.pwm)) { +- drm_err(&dev_priv->drm, "Failed to get the %s PWM chip\n", +- desc); +- panel->backlight.pwm = NULL; +- return -ENODEV; +- } +- +- panel->backlight.pwm_level_max = 100; /* 100% */ +- panel->backlight.pwm_level_min = get_backlight_min_vbt(connector); +- +- if (pwm_is_enabled(panel->backlight.pwm)) { +- /* PWM is already enabled, use existing settings */ +- pwm_get_state(panel->backlight.pwm, &panel->backlight.pwm_state); +- +- level = pwm_get_relative_duty_cycle(&panel->backlight.pwm_state, +- 100); +- level = intel_panel_invert_pwm_level(connector, level); +- panel->backlight.pwm_enabled = true; +- +- drm_dbg_kms(&dev_priv->drm, "PWM already enabled at freq %ld, VBT freq %d, level %d\n", +- NSEC_PER_SEC / (unsigned long)panel->backlight.pwm_state.period, +- get_vbt_pwm_freq(dev_priv), level); +- } else { +- /* Set period from VBT frequency, leave other settings at 0. */ +- panel->backlight.pwm_state.period = +- NSEC_PER_SEC / get_vbt_pwm_freq(dev_priv); +- } +- +- drm_info(&dev_priv->drm, "Using %s PWM for LCD backlight control\n", +- desc); +- return 0; +-} +- +-static void intel_pwm_set_backlight(const struct drm_connector_state *conn_state, u32 level) +-{ +- struct intel_connector *connector = to_intel_connector(conn_state->connector); +- struct intel_panel *panel = &connector->panel; +- +- panel->backlight.pwm_funcs->set(conn_state, +- intel_panel_invert_pwm_level(connector, level)); +-} +- +-static u32 intel_pwm_get_backlight(struct intel_connector *connector, enum pipe pipe) +-{ +- struct intel_panel *panel = &connector->panel; +- +- return intel_panel_invert_pwm_level(connector, +- panel->backlight.pwm_funcs->get(connector, pipe)); +-} +- +-static void intel_pwm_enable_backlight(const struct intel_crtc_state *crtc_state, +- const struct drm_connector_state *conn_state, u32 level) +-{ +- struct intel_connector *connector = to_intel_connector(conn_state->connector); +- struct intel_panel *panel = &connector->panel; +- +- panel->backlight.pwm_funcs->enable(crtc_state, conn_state, +- intel_panel_invert_pwm_level(connector, level)); +-} +- +-static void intel_pwm_disable_backlight(const struct drm_connector_state *conn_state, u32 level) +-{ +- struct intel_connector *connector = to_intel_connector(conn_state->connector); +- struct intel_panel *panel = &connector->panel; +- +- panel->backlight.pwm_funcs->disable(conn_state, +- intel_panel_invert_pwm_level(connector, level)); +-} +- +-static int intel_pwm_setup_backlight(struct intel_connector *connector, enum pipe pipe) +-{ +- struct intel_panel *panel = &connector->panel; +- int ret = panel->backlight.pwm_funcs->setup(connector, pipe); +- +- if (ret < 0) +- return ret; +- +- panel->backlight.min = panel->backlight.pwm_level_min; +- panel->backlight.max = panel->backlight.pwm_level_max; +- panel->backlight.level = intel_pwm_get_backlight(connector, pipe); +- panel->backlight.enabled = panel->backlight.pwm_enabled; +- +- return 0; +-} +- +-void intel_panel_update_backlight(struct intel_atomic_state *state, +- struct intel_encoder *encoder, +- const struct intel_crtc_state *crtc_state, +- const struct drm_connector_state *conn_state) +-{ +- struct intel_connector *connector = to_intel_connector(conn_state->connector); +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- struct intel_panel *panel = &connector->panel; +- +- if (!panel->backlight.present) +- return; +- +- mutex_lock(&dev_priv->backlight_lock); +- if (!panel->backlight.enabled) +- __intel_panel_enable_backlight(crtc_state, conn_state); +- +- mutex_unlock(&dev_priv->backlight_lock); +-} +- +-int intel_panel_setup_backlight(struct drm_connector *connector, enum pipe pipe) +-{ +- struct drm_i915_private *dev_priv = to_i915(connector->dev); +- struct intel_connector *intel_connector = to_intel_connector(connector); +- struct intel_panel *panel = &intel_connector->panel; +- int ret; +- +- if (!dev_priv->vbt.backlight.present) { +- if (dev_priv->quirks & QUIRK_BACKLIGHT_PRESENT) { +- drm_dbg_kms(&dev_priv->drm, +- "no backlight present per VBT, but present per quirk\n"); +- } else { +- drm_dbg_kms(&dev_priv->drm, +- "no backlight present per VBT\n"); +- return 0; +- } +- } +- +- /* ensure intel_panel has been initialized first */ +- if (drm_WARN_ON(&dev_priv->drm, !panel->backlight.funcs)) +- return -ENODEV; +- +- /* set level and max in panel struct */ +- mutex_lock(&dev_priv->backlight_lock); +- ret = panel->backlight.funcs->setup(intel_connector, pipe); +- mutex_unlock(&dev_priv->backlight_lock); +- +- if (ret) { +- drm_dbg_kms(&dev_priv->drm, +- "failed to setup backlight for connector %s\n", +- connector->name); +- return ret; +- } +- +- panel->backlight.present = true; +- +- drm_dbg_kms(&dev_priv->drm, +- "Connector %s backlight initialized, %s, brightness %u/%u\n", +- connector->name, +- enableddisabled(panel->backlight.enabled), +- panel->backlight.level, panel->backlight.max); +- +- return 0; +-} +- +-static void intel_panel_destroy_backlight(struct intel_panel *panel) +-{ +- /* dispose of the pwm */ +- if (panel->backlight.pwm) +- pwm_put(panel->backlight.pwm); +- +- panel->backlight.present = false; +-} +- +-static const struct intel_panel_bl_funcs bxt_pwm_funcs = { +- .setup = bxt_setup_backlight, +- .enable = bxt_enable_backlight, +- .disable = bxt_disable_backlight, +- .set = bxt_set_backlight, +- .get = bxt_get_backlight, +- .hz_to_pwm = bxt_hz_to_pwm, +-}; +- +-static const struct intel_panel_bl_funcs cnp_pwm_funcs = { +- .setup = cnp_setup_backlight, +- .enable = cnp_enable_backlight, +- .disable = cnp_disable_backlight, +- .set = bxt_set_backlight, +- .get = bxt_get_backlight, +- .hz_to_pwm = cnp_hz_to_pwm, +-}; +- +-static const struct intel_panel_bl_funcs lpt_pwm_funcs = { +- .setup = lpt_setup_backlight, +- .enable = lpt_enable_backlight, +- .disable = lpt_disable_backlight, +- .set = lpt_set_backlight, +- .get = lpt_get_backlight, +- .hz_to_pwm = lpt_hz_to_pwm, +-}; +- +-static const struct intel_panel_bl_funcs spt_pwm_funcs = { +- .setup = lpt_setup_backlight, +- .enable = lpt_enable_backlight, +- .disable = lpt_disable_backlight, +- .set = lpt_set_backlight, +- .get = lpt_get_backlight, +- .hz_to_pwm = spt_hz_to_pwm, +-}; +- +-static const struct intel_panel_bl_funcs pch_pwm_funcs = { +- .setup = pch_setup_backlight, +- .enable = pch_enable_backlight, +- .disable = pch_disable_backlight, +- .set = pch_set_backlight, +- .get = pch_get_backlight, +- .hz_to_pwm = pch_hz_to_pwm, +-}; +- +-static const struct intel_panel_bl_funcs ext_pwm_funcs = { +- .setup = ext_pwm_setup_backlight, +- .enable = ext_pwm_enable_backlight, +- .disable = ext_pwm_disable_backlight, +- .set = ext_pwm_set_backlight, +- .get = ext_pwm_get_backlight, +-}; +- +-static const struct intel_panel_bl_funcs vlv_pwm_funcs = { +- .setup = vlv_setup_backlight, +- .enable = vlv_enable_backlight, +- .disable = vlv_disable_backlight, +- .set = vlv_set_backlight, +- .get = vlv_get_backlight, +- .hz_to_pwm = vlv_hz_to_pwm, +-}; +- +-static const struct intel_panel_bl_funcs i965_pwm_funcs = { +- .setup = i965_setup_backlight, +- .enable = i965_enable_backlight, +- .disable = i965_disable_backlight, +- .set = i9xx_set_backlight, +- .get = i9xx_get_backlight, +- .hz_to_pwm = i965_hz_to_pwm, +-}; +- +-static const struct intel_panel_bl_funcs i9xx_pwm_funcs = { +- .setup = i9xx_setup_backlight, +- .enable = i9xx_enable_backlight, +- .disable = i9xx_disable_backlight, +- .set = i9xx_set_backlight, +- .get = i9xx_get_backlight, +- .hz_to_pwm = i9xx_hz_to_pwm, +-}; +- +-static const struct intel_panel_bl_funcs pwm_bl_funcs = { +- .setup = intel_pwm_setup_backlight, +- .enable = intel_pwm_enable_backlight, +- .disable = intel_pwm_disable_backlight, +- .set = intel_pwm_set_backlight, +- .get = intel_pwm_get_backlight, +-}; +- +-/* Set up chip specific backlight functions */ +-static void +-intel_panel_init_backlight_funcs(struct intel_panel *panel) +-{ +- struct intel_connector *connector = +- container_of(panel, struct intel_connector, panel); +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- +- if (connector->base.connector_type == DRM_MODE_CONNECTOR_DSI && +- intel_dsi_dcs_init_backlight_funcs(connector) == 0) +- return; +- +- if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) { +- panel->backlight.pwm_funcs = &bxt_pwm_funcs; +- } else if (INTEL_PCH_TYPE(dev_priv) >= PCH_CNP) { +- panel->backlight.pwm_funcs = &cnp_pwm_funcs; +- } else if (INTEL_PCH_TYPE(dev_priv) >= PCH_LPT) { +- if (HAS_PCH_LPT(dev_priv)) +- panel->backlight.pwm_funcs = &lpt_pwm_funcs; +- else +- panel->backlight.pwm_funcs = &spt_pwm_funcs; +- } else if (HAS_PCH_SPLIT(dev_priv)) { +- panel->backlight.pwm_funcs = &pch_pwm_funcs; +- } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { +- if (connector->base.connector_type == DRM_MODE_CONNECTOR_DSI) { +- panel->backlight.pwm_funcs = &ext_pwm_funcs; +- } else { +- panel->backlight.pwm_funcs = &vlv_pwm_funcs; +- } +- } else if (DISPLAY_VER(dev_priv) == 4) { +- panel->backlight.pwm_funcs = &i965_pwm_funcs; +- } else { +- panel->backlight.pwm_funcs = &i9xx_pwm_funcs; +- } +- +- if (connector->base.connector_type == DRM_MODE_CONNECTOR_eDP && +- intel_dp_aux_init_backlight_funcs(connector) == 0) +- return; +- +- /* We're using a standard PWM backlight interface */ +- panel->backlight.funcs = &pwm_bl_funcs; +-} +- + enum drm_connector_status + intel_panel_detect(struct drm_connector *connector, bool force) + { +diff --git a/drivers/gpu/drm/i915/display/intel_panel.h b/drivers/gpu/drm/i915/display/intel_panel.h +index 1d340f77bffc7..67dbb15026bf1 100644 +--- a/drivers/gpu/drm/i915/display/intel_panel.h ++++ b/drivers/gpu/drm/i915/display/intel_panel.h +@@ -8,15 +8,13 @@ + + #include <linux/types.h> + +-#include "intel_display.h" +- ++enum drm_connector_status; + struct drm_connector; + struct drm_connector_state; + struct drm_display_mode; ++struct drm_i915_private; + struct intel_connector; +-struct intel_crtc; + struct intel_crtc_state; +-struct intel_encoder; + struct intel_panel; + + int intel_panel_init(struct intel_panel *panel, +@@ -31,17 +29,6 @@ int intel_pch_panel_fitting(struct intel_crtc_state *crtc_state, + const struct drm_connector_state *conn_state); + int intel_gmch_panel_fitting(struct intel_crtc_state *crtc_state, + const struct drm_connector_state *conn_state); +-void intel_panel_set_backlight_acpi(const struct drm_connector_state *conn_state, +- u32 level, u32 max); +-int intel_panel_setup_backlight(struct drm_connector *connector, +- enum pipe pipe); +-void intel_panel_enable_backlight(const struct intel_crtc_state *crtc_state, +- const struct drm_connector_state *conn_state); +-void intel_panel_update_backlight(struct intel_atomic_state *state, +- struct intel_encoder *encoder, +- const struct intel_crtc_state *crtc_state, +- const struct drm_connector_state *conn_state); +-void intel_panel_disable_backlight(const struct drm_connector_state *old_conn_state); + struct drm_display_mode * + intel_panel_edid_downclock_mode(struct intel_connector *connector, + const struct drm_display_mode *fixed_mode); +@@ -49,22 +36,5 @@ struct drm_display_mode * + intel_panel_edid_fixed_mode(struct intel_connector *connector); + struct drm_display_mode * + intel_panel_vbt_fixed_mode(struct intel_connector *connector); +-void intel_panel_set_pwm_level(const struct drm_connector_state *conn_state, u32 level); +-u32 intel_panel_invert_pwm_level(struct intel_connector *connector, u32 level); +-u32 intel_panel_backlight_level_to_pwm(struct intel_connector *connector, u32 level); +-u32 intel_panel_backlight_level_from_pwm(struct intel_connector *connector, u32 val); +- +-#if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE) +-int intel_backlight_device_register(struct intel_connector *connector); +-void intel_backlight_device_unregister(struct intel_connector *connector); +-#else /* CONFIG_BACKLIGHT_CLASS_DEVICE */ +-static inline int intel_backlight_device_register(struct intel_connector *connector) +-{ +- return 0; +-} +-static inline void intel_backlight_device_unregister(struct intel_connector *connector) +-{ +-} +-#endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */ + + #endif /* __INTEL_PANEL_H__ */ +diff --git a/drivers/gpu/drm/i915/display/intel_quirks.c b/drivers/gpu/drm/i915/display/intel_quirks.c +index 8a52b7a167746..407b096f53921 100644 +--- a/drivers/gpu/drm/i915/display/intel_quirks.c ++++ b/drivers/gpu/drm/i915/display/intel_quirks.c +@@ -190,6 +190,9 @@ static struct intel_quirk intel_quirks[] = { + /* ASRock ITX*/ + { 0x3185, 0x1849, 0x2212, quirk_increase_ddi_disabled_time }, + { 0x3184, 0x1849, 0x2212, quirk_increase_ddi_disabled_time }, ++ /* ECS Liva Q2 */ ++ { 0x3185, 0x1019, 0xa94d, quirk_increase_ddi_disabled_time }, ++ { 0x3184, 0x1019, 0xa94d, quirk_increase_ddi_disabled_time }, + }; + + void intel_init_quirks(struct drm_i915_private *i915) +diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c +index 0ee4ff341e25d..b27738df447d0 100644 +--- a/drivers/gpu/drm/i915/display/vlv_dsi.c ++++ b/drivers/gpu/drm/i915/display/vlv_dsi.c +@@ -32,6 +32,7 @@ + + #include "i915_drv.h" + #include "intel_atomic.h" ++#include "intel_backlight.h" + #include "intel_connector.h" + #include "intel_crtc.h" + #include "intel_de.h" +diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c +index cde0a477fb497..7ed7dba42c834 100644 +--- a/drivers/gpu/drm/i915/gvt/handlers.c ++++ b/drivers/gpu/drm/i915/gvt/handlers.c +@@ -909,7 +909,7 @@ static int update_fdi_rx_iir_status(struct intel_vgpu *vgpu, + else if (FDI_RX_IMR_TO_PIPE(offset) != INVALID_INDEX) + index = FDI_RX_IMR_TO_PIPE(offset); + else { +- gvt_vgpu_err("Unsupport registers %x\n", offset); ++ gvt_vgpu_err("Unsupported registers %x\n", offset); + return -EINVAL; + } + +diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c +index 1a27e4833adfa..9123baf723d82 100644 +--- a/drivers/gpu/drm/i915/intel_pm.c ++++ b/drivers/gpu/drm/i915/intel_pm.c +@@ -6638,7 +6638,10 @@ void skl_wm_get_hw_state(struct drm_i915_private *dev_priv) + enum plane_id plane_id; + u8 slices; + +- skl_pipe_wm_get_hw_state(crtc, &crtc_state->wm.skl.optimal); ++ memset(&crtc_state->wm.skl.optimal, 0, ++ sizeof(crtc_state->wm.skl.optimal)); ++ if (crtc_state->hw.active) ++ skl_pipe_wm_get_hw_state(crtc, &crtc_state->wm.skl.optimal); + crtc_state->wm.skl.raw = crtc_state->wm.skl.optimal; + + memset(&dbuf_state->ddb[pipe], 0, sizeof(dbuf_state->ddb[pipe])); +@@ -6649,6 +6652,9 @@ void skl_wm_get_hw_state(struct drm_i915_private *dev_priv) + struct skl_ddb_entry *ddb_uv = + &crtc_state->wm.skl.plane_ddb_uv[plane_id]; + ++ if (!crtc_state->hw.active) ++ continue; ++ + skl_ddb_get_hw_plane_state(dev_priv, crtc->pipe, + plane_id, ddb_y, ddb_uv); + +diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c +index b6f4ce2a48afe..6d9eec98e0d38 100644 +--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c ++++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c +@@ -1198,7 +1198,7 @@ static int dp_ctrl_link_train_2(struct dp_ctrl_private *ctrl, + if (ret) + return ret; + +- dp_ctrl_train_pattern_set(ctrl, pattern | DP_RECOVERED_CLOCK_OUT_EN); ++ dp_ctrl_train_pattern_set(ctrl, pattern); + + for (tries = 0; tries <= maximum_retries; tries++) { + drm_dp_link_train_channel_eq_delay(ctrl->aux, ctrl->panel->dpcd); +diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.c b/drivers/gpu/drm/msm/dsi/dsi_cfg.c +index 96bbc8b6d0092..ce3901439c69c 100644 +--- a/drivers/gpu/drm/msm/dsi/dsi_cfg.c ++++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.c +@@ -109,7 +109,7 @@ static const char * const dsi_8996_bus_clk_names[] = { + static const struct msm_dsi_config msm8996_dsi_cfg = { + .io_offset = DSI_6G_REG_SHIFT, + .reg_cfg = { +- .num = 2, ++ .num = 3, + .regs = { + {"vdda", 18160, 1 }, /* 1.25 V */ + {"vcca", 17000, 32 }, /* 0.925 V */ +@@ -148,7 +148,7 @@ static const char * const dsi_sdm660_bus_clk_names[] = { + static const struct msm_dsi_config sdm660_dsi_cfg = { + .io_offset = DSI_6G_REG_SHIFT, + .reg_cfg = { +- .num = 2, ++ .num = 1, + .regs = { + {"vdda", 12560, 4 }, /* 1.2 V */ + }, +diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c +index a878b8b079c64..6a917fe69a833 100644 +--- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c ++++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c +@@ -347,7 +347,7 @@ int msm_dsi_dphy_timing_calc_v3(struct msm_dsi_dphy_timing *timing, + } else { + timing->shared_timings.clk_pre = + linear_inter(tmax, tmin, pcnt2, 0, false); +- timing->shared_timings.clk_pre_inc_by_2 = 0; ++ timing->shared_timings.clk_pre_inc_by_2 = 0; + } + + timing->ta_go = 3; +diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c +index befe989ca7b94..fbf3f5a4ecb67 100644 +--- a/drivers/hwmon/gpio-fan.c ++++ b/drivers/hwmon/gpio-fan.c +@@ -391,6 +391,9 @@ static int gpio_fan_set_cur_state(struct thermal_cooling_device *cdev, + if (!fan_data) + return -EINVAL; + ++ if (state >= fan_data->num_speed) ++ return -EINVAL; ++ + set_fan_speed(fan_data, state); + return 0; + } +diff --git a/drivers/iio/adc/ad7292.c b/drivers/iio/adc/ad7292.c +index 3271a31afde1c..e3e14a1253e89 100644 +--- a/drivers/iio/adc/ad7292.c ++++ b/drivers/iio/adc/ad7292.c +@@ -287,10 +287,8 @@ static int ad7292_probe(struct spi_device *spi) + + ret = devm_add_action_or_reset(&spi->dev, + ad7292_regulator_disable, st); +- if (ret) { +- regulator_disable(st->reg); ++ if (ret) + return ret; +- } + + ret = regulator_get_voltage(st->reg); + if (ret < 0) +diff --git a/drivers/iio/adc/mcp3911.c b/drivers/iio/adc/mcp3911.c +index e573da5397bb3..65278270a75ce 100644 +--- a/drivers/iio/adc/mcp3911.c ++++ b/drivers/iio/adc/mcp3911.c +@@ -38,8 +38,8 @@ + #define MCP3911_CHANNEL(x) (MCP3911_REG_CHANNEL0 + x * 3) + #define MCP3911_OFFCAL(x) (MCP3911_REG_OFFCAL_CH0 + x * 6) + +-/* Internal voltage reference in uV */ +-#define MCP3911_INT_VREF_UV 1200000 ++/* Internal voltage reference in mV */ ++#define MCP3911_INT_VREF_MV 1200 + + #define MCP3911_REG_READ(reg, id) ((((reg) << 1) | ((id) << 5) | (1 << 0)) & 0xff) + #define MCP3911_REG_WRITE(reg, id) ((((reg) << 1) | ((id) << 5) | (0 << 0)) & 0xff) +@@ -111,6 +111,8 @@ static int mcp3911_read_raw(struct iio_dev *indio_dev, + if (ret) + goto out; + ++ *val = sign_extend32(*val, 23); ++ + ret = IIO_VAL_INT; + break; + +@@ -135,11 +137,18 @@ static int mcp3911_read_raw(struct iio_dev *indio_dev, + + *val = ret / 1000; + } else { +- *val = MCP3911_INT_VREF_UV; ++ *val = MCP3911_INT_VREF_MV; + } + +- *val2 = 24; +- ret = IIO_VAL_FRACTIONAL_LOG2; ++ /* ++ * For 24bit Conversion ++ * Raw = ((Voltage)/(Vref) * 2^23 * Gain * 1.5 ++ * Voltage = Raw * (Vref)/(2^23 * Gain * 1.5) ++ */ ++ ++ /* val2 = (2^23 * 1.5) */ ++ *val2 = 12582912; ++ ret = IIO_VAL_FRACTIONAL; + break; + } + +diff --git a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c +index f95a81b9fac72..2380546d79782 100644 +--- a/drivers/input/joystick/iforce/iforce-serio.c ++++ b/drivers/input/joystick/iforce/iforce-serio.c +@@ -39,7 +39,7 @@ static void iforce_serio_xmit(struct iforce *iforce) + + again: + if (iforce->xmit.head == iforce->xmit.tail) { +- clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); ++ iforce_clear_xmit_and_wake(iforce); + spin_unlock_irqrestore(&iforce->xmit_lock, flags); + return; + } +@@ -64,7 +64,7 @@ again: + if (test_and_clear_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags)) + goto again; + +- clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); ++ iforce_clear_xmit_and_wake(iforce); + + spin_unlock_irqrestore(&iforce->xmit_lock, flags); + } +@@ -169,7 +169,7 @@ static irqreturn_t iforce_serio_irq(struct serio *serio, + iforce_serio->cmd_response_len = iforce_serio->len; + + /* Signal that command is done */ +- wake_up(&iforce->wait); ++ wake_up_all(&iforce->wait); + } else if (likely(iforce->type)) { + iforce_process_packet(iforce, iforce_serio->id, + iforce_serio->data_in, +diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c +index ea58805c480fa..cba92bd590a8d 100644 +--- a/drivers/input/joystick/iforce/iforce-usb.c ++++ b/drivers/input/joystick/iforce/iforce-usb.c +@@ -30,7 +30,7 @@ static void __iforce_usb_xmit(struct iforce *iforce) + spin_lock_irqsave(&iforce->xmit_lock, flags); + + if (iforce->xmit.head == iforce->xmit.tail) { +- clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); ++ iforce_clear_xmit_and_wake(iforce); + spin_unlock_irqrestore(&iforce->xmit_lock, flags); + return; + } +@@ -58,9 +58,9 @@ static void __iforce_usb_xmit(struct iforce *iforce) + XMIT_INC(iforce->xmit.tail, n); + + if ( (n=usb_submit_urb(iforce_usb->out, GFP_ATOMIC)) ) { +- clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); + dev_warn(&iforce_usb->intf->dev, + "usb_submit_urb failed %d\n", n); ++ iforce_clear_xmit_and_wake(iforce); + } + + /* The IFORCE_XMIT_RUNNING bit is not cleared here. That's intended. +@@ -175,15 +175,15 @@ static void iforce_usb_out(struct urb *urb) + struct iforce *iforce = &iforce_usb->iforce; + + if (urb->status) { +- clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); + dev_dbg(&iforce_usb->intf->dev, "urb->status %d, exiting\n", + urb->status); ++ iforce_clear_xmit_and_wake(iforce); + return; + } + + __iforce_usb_xmit(iforce); + +- wake_up(&iforce->wait); ++ wake_up_all(&iforce->wait); + } + + static int iforce_usb_probe(struct usb_interface *intf, +diff --git a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h +index 6aa761ebbdf77..9ccb9107ccbef 100644 +--- a/drivers/input/joystick/iforce/iforce.h ++++ b/drivers/input/joystick/iforce/iforce.h +@@ -119,6 +119,12 @@ static inline int iforce_get_id_packet(struct iforce *iforce, u8 id, + response_data, response_len); + } + ++static inline void iforce_clear_xmit_and_wake(struct iforce *iforce) ++{ ++ clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); ++ wake_up_all(&iforce->wait); ++} ++ + /* Public functions */ + /* iforce-main.c */ + int iforce_init_device(struct device *parent, u16 bustype, +diff --git a/drivers/input/misc/rk805-pwrkey.c b/drivers/input/misc/rk805-pwrkey.c +index 3fb64dbda1a21..76873aa005b41 100644 +--- a/drivers/input/misc/rk805-pwrkey.c ++++ b/drivers/input/misc/rk805-pwrkey.c +@@ -98,6 +98,7 @@ static struct platform_driver rk805_pwrkey_driver = { + }; + module_platform_driver(rk805_pwrkey_driver); + ++MODULE_ALIAS("platform:rk805-pwrkey"); + MODULE_AUTHOR("Joseph Chen <chenjh@rock-chips.com>"); + MODULE_DESCRIPTION("RK805 PMIC Power Key driver"); + MODULE_LICENSE("GPL"); +diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c +index 5f296f985b07a..deb3db45a94ce 100644 +--- a/drivers/media/rc/mceusb.c ++++ b/drivers/media/rc/mceusb.c +@@ -1416,42 +1416,37 @@ static void mceusb_gen1_init(struct mceusb_dev *ir) + { + int ret; + struct device *dev = ir->dev; +- char *data; +- +- data = kzalloc(USB_CTRL_MSG_SZ, GFP_KERNEL); +- if (!data) { +- dev_err(dev, "%s: memory allocation failed!", __func__); +- return; +- } ++ char data[USB_CTRL_MSG_SZ]; + + /* + * This is a strange one. Windows issues a set address to the device + * on the receive control pipe and expect a certain value pair back + */ +- ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0), +- USB_REQ_SET_ADDRESS, USB_TYPE_VENDOR, 0, 0, +- data, USB_CTRL_MSG_SZ, 3000); ++ ret = usb_control_msg_recv(ir->usbdev, 0, USB_REQ_SET_ADDRESS, ++ USB_DIR_IN | USB_TYPE_VENDOR, ++ 0, 0, data, USB_CTRL_MSG_SZ, 3000, ++ GFP_KERNEL); + dev_dbg(dev, "set address - ret = %d", ret); + dev_dbg(dev, "set address - data[0] = %d, data[1] = %d", + data[0], data[1]); + + /* set feature: bit rate 38400 bps */ +- ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), +- USB_REQ_SET_FEATURE, USB_TYPE_VENDOR, +- 0xc04e, 0x0000, NULL, 0, 3000); ++ ret = usb_control_msg_send(ir->usbdev, 0, ++ USB_REQ_SET_FEATURE, USB_TYPE_VENDOR, ++ 0xc04e, 0x0000, NULL, 0, 3000, GFP_KERNEL); + + dev_dbg(dev, "set feature - ret = %d", ret); + + /* bRequest 4: set char length to 8 bits */ +- ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), +- 4, USB_TYPE_VENDOR, +- 0x0808, 0x0000, NULL, 0, 3000); ++ ret = usb_control_msg_send(ir->usbdev, 0, ++ 4, USB_TYPE_VENDOR, ++ 0x0808, 0x0000, NULL, 0, 3000, GFP_KERNEL); + dev_dbg(dev, "set char length - retB = %d", ret); + + /* bRequest 2: set handshaking to use DTR/DSR */ +- ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), +- 2, USB_TYPE_VENDOR, +- 0x0000, 0x0100, NULL, 0, 3000); ++ ret = usb_control_msg_send(ir->usbdev, 0, ++ 2, USB_TYPE_VENDOR, ++ 0x0000, 0x0100, NULL, 0, 3000, GFP_KERNEL); + dev_dbg(dev, "set handshake - retC = %d", ret); + + /* device resume */ +@@ -1459,8 +1454,6 @@ static void mceusb_gen1_init(struct mceusb_dev *ir) + + /* get hw/sw revision? */ + mce_command_out(ir, GET_REVISION, sizeof(GET_REVISION)); +- +- kfree(data); + } + + static void mceusb_gen2_init(struct mceusb_dev *ir) +diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c +index c7134d2cf69a9..cf5705776c4f6 100644 +--- a/drivers/misc/fastrpc.c ++++ b/drivers/misc/fastrpc.c +@@ -1550,7 +1550,12 @@ static int fastrpc_cb_probe(struct platform_device *pdev) + of_property_read_u32(dev->of_node, "qcom,nsessions", &sessions); + + spin_lock_irqsave(&cctx->lock, flags); +- sess = &cctx->session[cctx->sesscount]; ++ if (cctx->sesscount >= FASTRPC_MAX_SESSIONS) { ++ dev_err(&pdev->dev, "too many sessions\n"); ++ spin_unlock_irqrestore(&cctx->lock, flags); ++ return -ENOSPC; ++ } ++ sess = &cctx->session[cctx->sesscount++]; + sess->used = false; + sess->valid = true; + sess->dev = dev; +@@ -1563,13 +1568,12 @@ static int fastrpc_cb_probe(struct platform_device *pdev) + struct fastrpc_session_ctx *dup_sess; + + for (i = 1; i < sessions; i++) { +- if (cctx->sesscount++ >= FASTRPC_MAX_SESSIONS) ++ if (cctx->sesscount >= FASTRPC_MAX_SESSIONS) + break; +- dup_sess = &cctx->session[cctx->sesscount]; ++ dup_sess = &cctx->session[cctx->sesscount++]; + memcpy(dup_sess, sess, sizeof(*dup_sess)); + } + } +- cctx->sesscount++; + spin_unlock_irqrestore(&cctx->lock, flags); + rc = dma_set_mask(dev, DMA_BIT_MASK(32)); + if (rc) { +diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c +index 44e134fa04afb..7e8d4abed602d 100644 +--- a/drivers/mmc/core/sd.c ++++ b/drivers/mmc/core/sd.c +@@ -942,15 +942,16 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card, + + /* Erase init depends on CSD and SSR */ + mmc_init_erase(card); +- +- /* +- * Fetch switch information from card. +- */ +- err = mmc_read_switch(card); +- if (err) +- return err; + } + ++ /* ++ * Fetch switch information from card. Note, sd3_bus_mode can change if ++ * voltage switch outcome changes, so do this always. ++ */ ++ err = mmc_read_switch(card); ++ if (err) ++ return err; ++ + /* + * For SPI, enable CRC as appropriate. + * This CRC enable is located AFTER the reading of the +@@ -1473,26 +1474,15 @@ retry: + if (!v18_fixup_failed && !mmc_host_is_spi(host) && mmc_host_uhs(host) && + mmc_sd_card_using_v18(card) && + host->ios.signal_voltage != MMC_SIGNAL_VOLTAGE_180) { +- /* +- * Re-read switch information in case it has changed since +- * oldcard was initialized. +- */ +- if (oldcard) { +- err = mmc_read_switch(card); +- if (err) +- goto free_card; +- } +- if (mmc_sd_card_using_v18(card)) { +- if (mmc_host_set_uhs_voltage(host) || +- mmc_sd_init_uhs_card(card)) { +- v18_fixup_failed = true; +- mmc_power_cycle(host, ocr); +- if (!oldcard) +- mmc_remove_card(card); +- goto retry; +- } +- goto done; ++ if (mmc_host_set_uhs_voltage(host) || ++ mmc_sd_init_uhs_card(card)) { ++ v18_fixup_failed = true; ++ mmc_power_cycle(host, ocr); ++ if (!oldcard) ++ mmc_remove_card(card); ++ goto retry; + } ++ goto cont; + } + + /* Initialization sequence for UHS-I cards */ +@@ -1527,7 +1517,7 @@ retry: + mmc_set_bus_width(host, MMC_BUS_WIDTH_4); + } + } +- ++cont: + if (!oldcard) { + /* Read/parse the extension registers. */ + err = sd_read_ext_regs(card); +@@ -1559,7 +1549,7 @@ retry: + err = -EINVAL; + goto free_card; + } +-done: ++ + host->card = card; + return 0; + +diff --git a/drivers/net/dsa/xrs700x/xrs700x.c b/drivers/net/dsa/xrs700x/xrs700x.c +index 469420941054e..cf363d5a30020 100644 +--- a/drivers/net/dsa/xrs700x/xrs700x.c ++++ b/drivers/net/dsa/xrs700x/xrs700x.c +@@ -108,6 +108,7 @@ static void xrs700x_read_port_counters(struct xrs700x *priv, int port) + { + struct xrs700x_port *p = &priv->ports[port]; + struct rtnl_link_stats64 stats; ++ unsigned long flags; + int i; + + memset(&stats, 0, sizeof(stats)); +@@ -137,9 +138,9 @@ static void xrs700x_read_port_counters(struct xrs700x *priv, int port) + */ + stats.rx_packets += stats.multicast; + +- u64_stats_update_begin(&p->syncp); ++ flags = u64_stats_update_begin_irqsave(&p->syncp); + p->stats64 = stats; +- u64_stats_update_end(&p->syncp); ++ u64_stats_update_end_irqrestore(&p->syncp, flags); + + mutex_unlock(&p->mib_mutex); + } +diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c +index 012ca11a38cc1..8361faf03e429 100644 +--- a/drivers/net/ethernet/cortina/gemini.c ++++ b/drivers/net/ethernet/cortina/gemini.c +@@ -1920,7 +1920,7 @@ static void gmac_get_stats64(struct net_device *netdev, + + /* Racing with RX NAPI */ + do { +- start = u64_stats_fetch_begin(&port->rx_stats_syncp); ++ start = u64_stats_fetch_begin_irq(&port->rx_stats_syncp); + + stats->rx_packets = port->stats.rx_packets; + stats->rx_bytes = port->stats.rx_bytes; +@@ -1932,11 +1932,11 @@ static void gmac_get_stats64(struct net_device *netdev, + stats->rx_crc_errors = port->stats.rx_crc_errors; + stats->rx_frame_errors = port->stats.rx_frame_errors; + +- } while (u64_stats_fetch_retry(&port->rx_stats_syncp, start)); ++ } while (u64_stats_fetch_retry_irq(&port->rx_stats_syncp, start)); + + /* Racing with MIB and TX completion interrupts */ + do { +- start = u64_stats_fetch_begin(&port->ir_stats_syncp); ++ start = u64_stats_fetch_begin_irq(&port->ir_stats_syncp); + + stats->tx_errors = port->stats.tx_errors; + stats->tx_packets = port->stats.tx_packets; +@@ -1946,15 +1946,15 @@ static void gmac_get_stats64(struct net_device *netdev, + stats->rx_missed_errors = port->stats.rx_missed_errors; + stats->rx_fifo_errors = port->stats.rx_fifo_errors; + +- } while (u64_stats_fetch_retry(&port->ir_stats_syncp, start)); ++ } while (u64_stats_fetch_retry_irq(&port->ir_stats_syncp, start)); + + /* Racing with hard_start_xmit */ + do { +- start = u64_stats_fetch_begin(&port->tx_stats_syncp); ++ start = u64_stats_fetch_begin_irq(&port->tx_stats_syncp); + + stats->tx_dropped = port->stats.tx_dropped; + +- } while (u64_stats_fetch_retry(&port->tx_stats_syncp, start)); ++ } while (u64_stats_fetch_retry_irq(&port->tx_stats_syncp, start)); + + stats->rx_dropped += stats->rx_missed_errors; + } +@@ -2032,18 +2032,18 @@ static void gmac_get_ethtool_stats(struct net_device *netdev, + /* Racing with MIB interrupt */ + do { + p = values; +- start = u64_stats_fetch_begin(&port->ir_stats_syncp); ++ start = u64_stats_fetch_begin_irq(&port->ir_stats_syncp); + + for (i = 0; i < RX_STATS_NUM; i++) + *p++ = port->hw_stats[i]; + +- } while (u64_stats_fetch_retry(&port->ir_stats_syncp, start)); ++ } while (u64_stats_fetch_retry_irq(&port->ir_stats_syncp, start)); + values = p; + + /* Racing with RX NAPI */ + do { + p = values; +- start = u64_stats_fetch_begin(&port->rx_stats_syncp); ++ start = u64_stats_fetch_begin_irq(&port->rx_stats_syncp); + + for (i = 0; i < RX_STATUS_NUM; i++) + *p++ = port->rx_stats[i]; +@@ -2051,13 +2051,13 @@ static void gmac_get_ethtool_stats(struct net_device *netdev, + *p++ = port->rx_csum_stats[i]; + *p++ = port->rx_napi_exits; + +- } while (u64_stats_fetch_retry(&port->rx_stats_syncp, start)); ++ } while (u64_stats_fetch_retry_irq(&port->rx_stats_syncp, start)); + values = p; + + /* Racing with TX start_xmit */ + do { + p = values; +- start = u64_stats_fetch_begin(&port->tx_stats_syncp); ++ start = u64_stats_fetch_begin_irq(&port->tx_stats_syncp); + + for (i = 0; i < TX_MAX_FRAGS; i++) { + *values++ = port->tx_frag_stats[i]; +@@ -2066,7 +2066,7 @@ static void gmac_get_ethtool_stats(struct net_device *netdev, + *values++ = port->tx_frags_linearized; + *values++ = port->tx_hw_csummed; + +- } while (u64_stats_fetch_retry(&port->tx_stats_syncp, start)); ++ } while (u64_stats_fetch_retry_irq(&port->tx_stats_syncp, start)); + } + + static int gmac_get_ksettings(struct net_device *netdev, +diff --git a/drivers/net/ethernet/google/gve/gve_ethtool.c b/drivers/net/ethernet/google/gve/gve_ethtool.c +index 716e6240305d9..878329ddcf8df 100644 +--- a/drivers/net/ethernet/google/gve/gve_ethtool.c ++++ b/drivers/net/ethernet/google/gve/gve_ethtool.c +@@ -174,14 +174,14 @@ gve_get_ethtool_stats(struct net_device *netdev, + struct gve_rx_ring *rx = &priv->rx[ring]; + + start = +- u64_stats_fetch_begin(&priv->rx[ring].statss); ++ u64_stats_fetch_begin_irq(&priv->rx[ring].statss); + tmp_rx_pkts = rx->rpackets; + tmp_rx_bytes = rx->rbytes; + tmp_rx_skb_alloc_fail = rx->rx_skb_alloc_fail; + tmp_rx_buf_alloc_fail = rx->rx_buf_alloc_fail; + tmp_rx_desc_err_dropped_pkt = + rx->rx_desc_err_dropped_pkt; +- } while (u64_stats_fetch_retry(&priv->rx[ring].statss, ++ } while (u64_stats_fetch_retry_irq(&priv->rx[ring].statss, + start)); + rx_pkts += tmp_rx_pkts; + rx_bytes += tmp_rx_bytes; +@@ -195,10 +195,10 @@ gve_get_ethtool_stats(struct net_device *netdev, + if (priv->tx) { + do { + start = +- u64_stats_fetch_begin(&priv->tx[ring].statss); ++ u64_stats_fetch_begin_irq(&priv->tx[ring].statss); + tmp_tx_pkts = priv->tx[ring].pkt_done; + tmp_tx_bytes = priv->tx[ring].bytes_done; +- } while (u64_stats_fetch_retry(&priv->tx[ring].statss, ++ } while (u64_stats_fetch_retry_irq(&priv->tx[ring].statss, + start)); + tx_pkts += tmp_tx_pkts; + tx_bytes += tmp_tx_bytes; +@@ -256,13 +256,13 @@ gve_get_ethtool_stats(struct net_device *netdev, + data[i++] = rx->cnt; + do { + start = +- u64_stats_fetch_begin(&priv->rx[ring].statss); ++ u64_stats_fetch_begin_irq(&priv->rx[ring].statss); + tmp_rx_bytes = rx->rbytes; + tmp_rx_skb_alloc_fail = rx->rx_skb_alloc_fail; + tmp_rx_buf_alloc_fail = rx->rx_buf_alloc_fail; + tmp_rx_desc_err_dropped_pkt = + rx->rx_desc_err_dropped_pkt; +- } while (u64_stats_fetch_retry(&priv->rx[ring].statss, ++ } while (u64_stats_fetch_retry_irq(&priv->rx[ring].statss, + start)); + data[i++] = tmp_rx_bytes; + /* rx dropped packets */ +@@ -323,9 +323,9 @@ gve_get_ethtool_stats(struct net_device *netdev, + } + do { + start = +- u64_stats_fetch_begin(&priv->tx[ring].statss); ++ u64_stats_fetch_begin_irq(&priv->tx[ring].statss); + tmp_tx_bytes = tx->bytes_done; +- } while (u64_stats_fetch_retry(&priv->tx[ring].statss, ++ } while (u64_stats_fetch_retry_irq(&priv->tx[ring].statss, + start)); + data[i++] = tmp_tx_bytes; + data[i++] = tx->wake_queue; +diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c +index 68552848d3888..49850cf7cfafd 100644 +--- a/drivers/net/ethernet/google/gve/gve_main.c ++++ b/drivers/net/ethernet/google/gve/gve_main.c +@@ -51,10 +51,10 @@ static void gve_get_stats(struct net_device *dev, struct rtnl_link_stats64 *s) + for (ring = 0; ring < priv->rx_cfg.num_queues; ring++) { + do { + start = +- u64_stats_fetch_begin(&priv->rx[ring].statss); ++ u64_stats_fetch_begin_irq(&priv->rx[ring].statss); + packets = priv->rx[ring].rpackets; + bytes = priv->rx[ring].rbytes; +- } while (u64_stats_fetch_retry(&priv->rx[ring].statss, ++ } while (u64_stats_fetch_retry_irq(&priv->rx[ring].statss, + start)); + s->rx_packets += packets; + s->rx_bytes += bytes; +@@ -64,10 +64,10 @@ static void gve_get_stats(struct net_device *dev, struct rtnl_link_stats64 *s) + for (ring = 0; ring < priv->tx_cfg.num_queues; ring++) { + do { + start = +- u64_stats_fetch_begin(&priv->tx[ring].statss); ++ u64_stats_fetch_begin_irq(&priv->tx[ring].statss); + packets = priv->tx[ring].pkt_done; + bytes = priv->tx[ring].bytes_done; +- } while (u64_stats_fetch_retry(&priv->tx[ring].statss, ++ } while (u64_stats_fetch_retry_irq(&priv->tx[ring].statss, + start)); + s->tx_packets += packets; + s->tx_bytes += bytes; +@@ -1260,9 +1260,9 @@ void gve_handle_report_stats(struct gve_priv *priv) + } + + do { +- start = u64_stats_fetch_begin(&priv->tx[idx].statss); ++ start = u64_stats_fetch_begin_irq(&priv->tx[idx].statss); + tx_bytes = priv->tx[idx].bytes_done; +- } while (u64_stats_fetch_retry(&priv->tx[idx].statss, start)); ++ } while (u64_stats_fetch_retry_irq(&priv->tx[idx].statss, start)); + stats[stats_idx++] = (struct stats) { + .stat_name = cpu_to_be32(TX_WAKE_CNT), + .value = cpu_to_be64(priv->tx[idx].wake_queue), +diff --git a/drivers/net/ethernet/huawei/hinic/hinic_rx.c b/drivers/net/ethernet/huawei/hinic/hinic_rx.c +index a102d486c4350..d11ec69a2e17d 100644 +--- a/drivers/net/ethernet/huawei/hinic/hinic_rx.c ++++ b/drivers/net/ethernet/huawei/hinic/hinic_rx.c +@@ -74,14 +74,14 @@ void hinic_rxq_get_stats(struct hinic_rxq *rxq, struct hinic_rxq_stats *stats) + unsigned int start; + + do { +- start = u64_stats_fetch_begin(&rxq_stats->syncp); ++ start = u64_stats_fetch_begin_irq(&rxq_stats->syncp); + stats->pkts = rxq_stats->pkts; + stats->bytes = rxq_stats->bytes; + stats->errors = rxq_stats->csum_errors + + rxq_stats->other_errors; + stats->csum_errors = rxq_stats->csum_errors; + stats->other_errors = rxq_stats->other_errors; +- } while (u64_stats_fetch_retry(&rxq_stats->syncp, start)); ++ } while (u64_stats_fetch_retry_irq(&rxq_stats->syncp, start)); + } + + /** +diff --git a/drivers/net/ethernet/huawei/hinic/hinic_tx.c b/drivers/net/ethernet/huawei/hinic/hinic_tx.c +index d1ea358a1fc06..8d3ec6c729cc7 100644 +--- a/drivers/net/ethernet/huawei/hinic/hinic_tx.c ++++ b/drivers/net/ethernet/huawei/hinic/hinic_tx.c +@@ -98,14 +98,14 @@ void hinic_txq_get_stats(struct hinic_txq *txq, struct hinic_txq_stats *stats) + unsigned int start; + + do { +- start = u64_stats_fetch_begin(&txq_stats->syncp); ++ start = u64_stats_fetch_begin_irq(&txq_stats->syncp); + stats->pkts = txq_stats->pkts; + stats->bytes = txq_stats->bytes; + stats->tx_busy = txq_stats->tx_busy; + stats->tx_wake = txq_stats->tx_wake; + stats->tx_dropped = txq_stats->tx_dropped; + stats->big_frags_pkts = txq_stats->big_frags_pkts; +- } while (u64_stats_fetch_retry(&txq_stats->syncp, start)); ++ } while (u64_stats_fetch_retry_irq(&txq_stats->syncp, start)); + } + + /** +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h +index e3509e69ed1c6..3e8725b7f0b70 100644 +--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h +@@ -80,6 +80,7 @@ struct mlxbf_gige { + struct net_device *netdev; + struct platform_device *pdev; + void __iomem *mdio_io; ++ void __iomem *clk_io; + struct mii_bus *mdiobus; + void __iomem *gpio_io; + struct irq_domain *irqdomain; +@@ -149,7 +150,8 @@ enum mlxbf_gige_res { + MLXBF_GIGE_RES_MDIO9, + MLXBF_GIGE_RES_GPIO0, + MLXBF_GIGE_RES_LLU, +- MLXBF_GIGE_RES_PLU ++ MLXBF_GIGE_RES_PLU, ++ MLXBF_GIGE_RES_CLK + }; + + /* Version of register data returned by mlxbf_gige_get_regs() */ +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c +index 7905179a95753..f979ba7e5effc 100644 +--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c +@@ -22,10 +22,23 @@ + #include <linux/property.h> + + #include "mlxbf_gige.h" ++#include "mlxbf_gige_regs.h" + + #define MLXBF_GIGE_MDIO_GW_OFFSET 0x0 + #define MLXBF_GIGE_MDIO_CFG_OFFSET 0x4 + ++#define MLXBF_GIGE_MDIO_FREQ_REFERENCE 156250000ULL ++#define MLXBF_GIGE_MDIO_COREPLL_CONST 16384ULL ++#define MLXBF_GIGE_MDC_CLK_NS 400 ++#define MLXBF_GIGE_MDIO_PLL_I1CLK_REG1 0x4 ++#define MLXBF_GIGE_MDIO_PLL_I1CLK_REG2 0x8 ++#define MLXBF_GIGE_MDIO_CORE_F_SHIFT 0 ++#define MLXBF_GIGE_MDIO_CORE_F_MASK GENMASK(25, 0) ++#define MLXBF_GIGE_MDIO_CORE_R_SHIFT 26 ++#define MLXBF_GIGE_MDIO_CORE_R_MASK GENMASK(31, 26) ++#define MLXBF_GIGE_MDIO_CORE_OD_SHIFT 0 ++#define MLXBF_GIGE_MDIO_CORE_OD_MASK GENMASK(3, 0) ++ + /* Support clause 22 */ + #define MLXBF_GIGE_MDIO_CL22_ST1 0x1 + #define MLXBF_GIGE_MDIO_CL22_WRITE 0x1 +@@ -50,27 +63,76 @@ + #define MLXBF_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK GENMASK(23, 16) + #define MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK GENMASK(31, 24) + ++#define MLXBF_GIGE_MDIO_CFG_VAL (FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_MODE_MASK, 1) | \ ++ FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO3_3_MASK, 1) | \ ++ FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_MASK, 1) | \ ++ FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK, 6) | \ ++ FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK, 13)) ++ ++#define MLXBF_GIGE_BF2_COREPLL_ADDR 0x02800c30 ++#define MLXBF_GIGE_BF2_COREPLL_SIZE 0x0000000c ++ ++static struct resource corepll_params[] = { ++ [MLXBF_GIGE_VERSION_BF2] = { ++ .start = MLXBF_GIGE_BF2_COREPLL_ADDR, ++ .end = MLXBF_GIGE_BF2_COREPLL_ADDR + MLXBF_GIGE_BF2_COREPLL_SIZE - 1, ++ .name = "COREPLL_RES" ++ }, ++}; ++ ++/* Returns core clock i1clk in Hz */ ++static u64 calculate_i1clk(struct mlxbf_gige *priv) ++{ ++ u8 core_od, core_r; ++ u64 freq_output; ++ u32 reg1, reg2; ++ u32 core_f; ++ ++ reg1 = readl(priv->clk_io + MLXBF_GIGE_MDIO_PLL_I1CLK_REG1); ++ reg2 = readl(priv->clk_io + MLXBF_GIGE_MDIO_PLL_I1CLK_REG2); ++ ++ core_f = (reg1 & MLXBF_GIGE_MDIO_CORE_F_MASK) >> ++ MLXBF_GIGE_MDIO_CORE_F_SHIFT; ++ core_r = (reg1 & MLXBF_GIGE_MDIO_CORE_R_MASK) >> ++ MLXBF_GIGE_MDIO_CORE_R_SHIFT; ++ core_od = (reg2 & MLXBF_GIGE_MDIO_CORE_OD_MASK) >> ++ MLXBF_GIGE_MDIO_CORE_OD_SHIFT; ++ ++ /* Compute PLL output frequency as follow: ++ * ++ * CORE_F / 16384 ++ * freq_output = freq_reference * ---------------------------- ++ * (CORE_R + 1) * (CORE_OD + 1) ++ */ ++ freq_output = div_u64((MLXBF_GIGE_MDIO_FREQ_REFERENCE * core_f), ++ MLXBF_GIGE_MDIO_COREPLL_CONST); ++ freq_output = div_u64(freq_output, (core_r + 1) * (core_od + 1)); ++ ++ return freq_output; ++} ++ + /* Formula for encoding the MDIO period. The encoded value is + * passed to the MDIO config register. + * +- * mdc_clk = 2*(val + 1)*i1clk ++ * mdc_clk = 2*(val + 1)*(core clock in sec) + * +- * 400 ns = 2*(val + 1)*(((1/430)*1000) ns) ++ * i1clk is in Hz: ++ * 400 ns = 2*(val + 1)*(1/i1clk) + * +- * val = (((400 * 430 / 1000) / 2) - 1) ++ * val = (((400/10^9) / (1/i1clk) / 2) - 1) ++ * val = (400/2 * i1clk)/10^9 - 1 + */ +-#define MLXBF_GIGE_I1CLK_MHZ 430 +-#define MLXBF_GIGE_MDC_CLK_NS 400 ++static u8 mdio_period_map(struct mlxbf_gige *priv) ++{ ++ u8 mdio_period; ++ u64 i1clk; + +-#define MLXBF_GIGE_MDIO_PERIOD (((MLXBF_GIGE_MDC_CLK_NS * MLXBF_GIGE_I1CLK_MHZ / 1000) / 2) - 1) ++ i1clk = calculate_i1clk(priv); + +-#define MLXBF_GIGE_MDIO_CFG_VAL (FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_MODE_MASK, 1) | \ +- FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO3_3_MASK, 1) | \ +- FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_MASK, 1) | \ +- FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDC_PERIOD_MASK, \ +- MLXBF_GIGE_MDIO_PERIOD) | \ +- FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK, 6) | \ +- FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK, 13)) ++ mdio_period = div_u64((MLXBF_GIGE_MDC_CLK_NS >> 1) * i1clk, 1000000000) - 1; ++ ++ return mdio_period; ++} + + static u32 mlxbf_gige_mdio_create_cmd(u16 data, int phy_add, + int phy_reg, u32 opcode) +@@ -123,9 +185,9 @@ static int mlxbf_gige_mdio_write(struct mii_bus *bus, int phy_add, + int phy_reg, u16 val) + { + struct mlxbf_gige *priv = bus->priv; ++ u32 temp; + u32 cmd; + int ret; +- u32 temp; + + if (phy_reg & MII_ADDR_C45) + return -EOPNOTSUPP; +@@ -142,18 +204,44 @@ static int mlxbf_gige_mdio_write(struct mii_bus *bus, int phy_add, + return ret; + } + ++static void mlxbf_gige_mdio_cfg(struct mlxbf_gige *priv) ++{ ++ u8 mdio_period; ++ u32 val; ++ ++ mdio_period = mdio_period_map(priv); ++ ++ val = MLXBF_GIGE_MDIO_CFG_VAL; ++ val |= FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDC_PERIOD_MASK, mdio_period); ++ writel(val, priv->mdio_io + MLXBF_GIGE_MDIO_CFG_OFFSET); ++} ++ + int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv) + { + struct device *dev = &pdev->dev; ++ struct resource *res; + int ret; + + priv->mdio_io = devm_platform_ioremap_resource(pdev, MLXBF_GIGE_RES_MDIO9); + if (IS_ERR(priv->mdio_io)) + return PTR_ERR(priv->mdio_io); + +- /* Configure mdio parameters */ +- writel(MLXBF_GIGE_MDIO_CFG_VAL, +- priv->mdio_io + MLXBF_GIGE_MDIO_CFG_OFFSET); ++ /* clk resource shared with other drivers so cannot use ++ * devm_platform_ioremap_resource ++ */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_CLK); ++ if (!res) { ++ /* For backward compatibility with older ACPI tables, also keep ++ * CLK resource internal to the driver. ++ */ ++ res = &corepll_params[MLXBF_GIGE_VERSION_BF2]; ++ } ++ ++ priv->clk_io = devm_ioremap(dev, res->start, resource_size(res)); ++ if (IS_ERR(priv->clk_io)) ++ return PTR_ERR(priv->clk_io); ++ ++ mlxbf_gige_mdio_cfg(priv); + + priv->mdiobus = devm_mdiobus_alloc(dev); + if (!priv->mdiobus) { +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h +index 5fb33c9294bf9..7be3a793984d5 100644 +--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h +@@ -8,6 +8,8 @@ + #ifndef __MLXBF_GIGE_REGS_H__ + #define __MLXBF_GIGE_REGS_H__ + ++#define MLXBF_GIGE_VERSION 0x0000 ++#define MLXBF_GIGE_VERSION_BF2 0x0 + #define MLXBF_GIGE_STATUS 0x0010 + #define MLXBF_GIGE_STATUS_READY BIT(0) + #define MLXBF_GIGE_INT_STATUS 0x0028 +diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_packet.c b/drivers/net/ethernet/microchip/sparx5/sparx5_packet.c +index 148d431fcde42..c460168131c26 100644 +--- a/drivers/net/ethernet/microchip/sparx5/sparx5_packet.c ++++ b/drivers/net/ethernet/microchip/sparx5/sparx5_packet.c +@@ -107,6 +107,8 @@ static void sparx5_xtr_grp(struct sparx5 *sparx5, u8 grp, bool byte_swap) + /* This assumes STATUS_WORD_POS == 1, Status + * just after last data + */ ++ if (!byte_swap) ++ val = ntohl((__force __be32)val); + byte_cnt -= (4 - XTR_VALID_BYTES(val)); + eof_flag = true; + break; +diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +index 850bfdf83d0a4..69ac205bbdbd0 100644 +--- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c ++++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +@@ -3482,21 +3482,21 @@ static void nfp_net_stat64(struct net_device *netdev, + unsigned int start; + + do { +- start = u64_stats_fetch_begin(&r_vec->rx_sync); ++ start = u64_stats_fetch_begin_irq(&r_vec->rx_sync); + data[0] = r_vec->rx_pkts; + data[1] = r_vec->rx_bytes; + data[2] = r_vec->rx_drops; +- } while (u64_stats_fetch_retry(&r_vec->rx_sync, start)); ++ } while (u64_stats_fetch_retry_irq(&r_vec->rx_sync, start)); + stats->rx_packets += data[0]; + stats->rx_bytes += data[1]; + stats->rx_dropped += data[2]; + + do { +- start = u64_stats_fetch_begin(&r_vec->tx_sync); ++ start = u64_stats_fetch_begin_irq(&r_vec->tx_sync); + data[0] = r_vec->tx_pkts; + data[1] = r_vec->tx_bytes; + data[2] = r_vec->tx_errors; +- } while (u64_stats_fetch_retry(&r_vec->tx_sync, start)); ++ } while (u64_stats_fetch_retry_irq(&r_vec->tx_sync, start)); + stats->tx_packets += data[0]; + stats->tx_bytes += data[1]; + stats->tx_errors += data[2]; +diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c +index ae72cde713438..62546d197bfd2 100644 +--- a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c ++++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c +@@ -483,7 +483,7 @@ static u64 *nfp_vnic_get_sw_stats(struct net_device *netdev, u64 *data) + unsigned int start; + + do { +- start = u64_stats_fetch_begin(&nn->r_vecs[i].rx_sync); ++ start = u64_stats_fetch_begin_irq(&nn->r_vecs[i].rx_sync); + data[0] = nn->r_vecs[i].rx_pkts; + tmp[0] = nn->r_vecs[i].hw_csum_rx_ok; + tmp[1] = nn->r_vecs[i].hw_csum_rx_inner_ok; +@@ -491,10 +491,10 @@ static u64 *nfp_vnic_get_sw_stats(struct net_device *netdev, u64 *data) + tmp[3] = nn->r_vecs[i].hw_csum_rx_error; + tmp[4] = nn->r_vecs[i].rx_replace_buf_alloc_fail; + tmp[5] = nn->r_vecs[i].hw_tls_rx; +- } while (u64_stats_fetch_retry(&nn->r_vecs[i].rx_sync, start)); ++ } while (u64_stats_fetch_retry_irq(&nn->r_vecs[i].rx_sync, start)); + + do { +- start = u64_stats_fetch_begin(&nn->r_vecs[i].tx_sync); ++ start = u64_stats_fetch_begin_irq(&nn->r_vecs[i].tx_sync); + data[1] = nn->r_vecs[i].tx_pkts; + data[2] = nn->r_vecs[i].tx_busy; + tmp[6] = nn->r_vecs[i].hw_csum_tx; +@@ -504,7 +504,7 @@ static u64 *nfp_vnic_get_sw_stats(struct net_device *netdev, u64 *data) + tmp[10] = nn->r_vecs[i].hw_tls_tx; + tmp[11] = nn->r_vecs[i].tls_tx_fallback; + tmp[12] = nn->r_vecs[i].tls_tx_no_fallback; +- } while (u64_stats_fetch_retry(&nn->r_vecs[i].tx_sync, start)); ++ } while (u64_stats_fetch_retry_irq(&nn->r_vecs[i].tx_sync, start)); + + data += NN_RVEC_PER_Q_STATS; + +diff --git a/drivers/net/ethernet/rocker/rocker_ofdpa.c b/drivers/net/ethernet/rocker/rocker_ofdpa.c +index bc70c6abd6a5b..58cf7cc54f408 100644 +--- a/drivers/net/ethernet/rocker/rocker_ofdpa.c ++++ b/drivers/net/ethernet/rocker/rocker_ofdpa.c +@@ -1273,7 +1273,7 @@ static int ofdpa_port_ipv4_neigh(struct ofdpa_port *ofdpa_port, + bool removing; + int err = 0; + +- entry = kzalloc(sizeof(*entry), GFP_KERNEL); ++ entry = kzalloc(sizeof(*entry), GFP_ATOMIC); + if (!entry) + return -ENOMEM; + +diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c +index 592e191adbf7d..63b99dd8ca51c 100644 +--- a/drivers/net/ethernet/smsc/smsc911x.c ++++ b/drivers/net/ethernet/smsc/smsc911x.c +@@ -1037,6 +1037,8 @@ static int smsc911x_mii_probe(struct net_device *dev) + return ret; + } + ++ /* Indicate that the MAC is responsible for managing PHY PM */ ++ phydev->mac_managed_pm = true; + phy_attached_info(phydev); + + phy_set_max_speed(phydev, SPEED_100); +@@ -2584,6 +2586,8 @@ static int smsc911x_suspend(struct device *dev) + if (netif_running(ndev)) { + netif_stop_queue(ndev); + netif_device_detach(ndev); ++ if (!device_may_wakeup(dev)) ++ phy_stop(ndev->phydev); + } + + /* enable wake on LAN, energy detection and the external PME +@@ -2625,6 +2629,8 @@ static int smsc911x_resume(struct device *dev) + if (netif_running(ndev)) { + netif_device_attach(ndev); + netif_start_queue(ndev); ++ if (!device_may_wakeup(dev)) ++ phy_start(ndev->phydev); + } + + return 0; +diff --git a/drivers/net/ieee802154/adf7242.c b/drivers/net/ieee802154/adf7242.c +index 7db9cbd0f5ded..07adbeec19787 100644 +--- a/drivers/net/ieee802154/adf7242.c ++++ b/drivers/net/ieee802154/adf7242.c +@@ -1310,10 +1310,11 @@ static int adf7242_remove(struct spi_device *spi) + + debugfs_remove_recursive(lp->debugfs_root); + ++ ieee802154_unregister_hw(lp->hw); ++ + cancel_delayed_work_sync(&lp->work); + destroy_workqueue(lp->wqueue); + +- ieee802154_unregister_hw(lp->hw); + mutex_destroy(&lp->bmux); + ieee802154_free_hw(lp->hw); + +diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c +index 50572e0f1f529..84741715f6705 100644 +--- a/drivers/net/netdevsim/netdev.c ++++ b/drivers/net/netdevsim/netdev.c +@@ -67,10 +67,10 @@ nsim_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) + unsigned int start; + + do { +- start = u64_stats_fetch_begin(&ns->syncp); ++ start = u64_stats_fetch_begin_irq(&ns->syncp); + stats->tx_bytes = ns->tx_bytes; + stats->tx_packets = ns->tx_packets; +- } while (u64_stats_fetch_retry(&ns->syncp, start)); ++ } while (u64_stats_fetch_retry_irq(&ns->syncp, start)); + } + + static int +diff --git a/drivers/platform/x86/pmc_atom.c b/drivers/platform/x86/pmc_atom.c +index a9d2a4b98e570..4b0739f95f8b9 100644 +--- a/drivers/platform/x86/pmc_atom.c ++++ b/drivers/platform/x86/pmc_atom.c +@@ -244,7 +244,7 @@ static void pmc_power_off(void) + pm1_cnt_port = acpi_base_addr + PM1_CNT; + + pm1_cnt_value = inl(pm1_cnt_port); +- pm1_cnt_value &= SLEEP_TYPE_MASK; ++ pm1_cnt_value &= ~SLEEP_TYPE_MASK; + pm1_cnt_value |= SLEEP_TYPE_S5; + pm1_cnt_value |= SLEEP_ENABLE; + +diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c +index 2adc0a75c0515..1ce6f948e9a42 100644 +--- a/drivers/soundwire/qcom.c ++++ b/drivers/soundwire/qcom.c +@@ -148,7 +148,7 @@ struct qcom_swrm_ctrl { + u8 wcmd_id; + struct qcom_swrm_port_config pconfig[QCOM_SDW_MAX_PORTS]; + struct sdw_stream_runtime *sruntime[SWRM_MAX_DAIS]; +- enum sdw_slave_status status[SDW_MAX_DEVICES]; ++ enum sdw_slave_status status[SDW_MAX_DEVICES + 1]; + int (*reg_read)(struct qcom_swrm_ctrl *ctrl, int reg, u32 *val); + int (*reg_write)(struct qcom_swrm_ctrl *ctrl, int reg, int val); + u32 slave_status; +@@ -391,7 +391,7 @@ static int qcom_swrm_get_alert_slave_dev_num(struct qcom_swrm_ctrl *ctrl) + + ctrl->reg_read(ctrl, SWRM_MCP_SLV_STATUS, &val); + +- for (dev_num = 0; dev_num < SDW_MAX_DEVICES; dev_num++) { ++ for (dev_num = 0; dev_num <= SDW_MAX_DEVICES; dev_num++) { + status = (val >> (dev_num * SWRM_MCP_SLV_STATUS_SZ)); + + if ((status & SWRM_MCP_SLV_STATUS_MASK) == SDW_SLAVE_ALERT) { +@@ -411,7 +411,7 @@ static void qcom_swrm_get_device_status(struct qcom_swrm_ctrl *ctrl) + ctrl->reg_read(ctrl, SWRM_MCP_SLV_STATUS, &val); + ctrl->slave_status = val; + +- for (i = 0; i < SDW_MAX_DEVICES; i++) { ++ for (i = 0; i <= SDW_MAX_DEVICES; i++) { + u32 s; + + s = (val >> (i * 2)); +diff --git a/drivers/staging/r8188eu/os_dep/os_intfs.c b/drivers/staging/r8188eu/os_dep/os_intfs.c +index 8d0158f4a45d0..30caa1139c8eb 100644 +--- a/drivers/staging/r8188eu/os_dep/os_intfs.c ++++ b/drivers/staging/r8188eu/os_dep/os_intfs.c +@@ -17,6 +17,7 @@ MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("Realtek Wireless Lan Driver"); + MODULE_AUTHOR("Realtek Semiconductor Corp."); + MODULE_VERSION(DRIVERVERSION); ++MODULE_FIRMWARE("rtlwifi/rtl8188eufw.bin"); + + #define CONFIG_BR_EXT_BRNAME "br0" + #define RTW_NOTCH_FILTER 0 /* 0:Disable, 1:Enable, */ +diff --git a/drivers/staging/rtl8712/rtl8712_cmd.c b/drivers/staging/rtl8712/rtl8712_cmd.c +index e9294e1ed06eb..eacf5efa34307 100644 +--- a/drivers/staging/rtl8712/rtl8712_cmd.c ++++ b/drivers/staging/rtl8712/rtl8712_cmd.c +@@ -117,34 +117,6 @@ static void r871x_internal_cmd_hdl(struct _adapter *padapter, u8 *pbuf) + kfree(pdrvcmd->pbuf); + } + +-static u8 read_macreg_hdl(struct _adapter *padapter, u8 *pbuf) +-{ +- void (*pcmd_callback)(struct _adapter *dev, struct cmd_obj *pcmd); +- struct cmd_obj *pcmd = (struct cmd_obj *)pbuf; +- +- /* invoke cmd->callback function */ +- pcmd_callback = cmd_callback[pcmd->cmdcode].callback; +- if (!pcmd_callback) +- r8712_free_cmd_obj(pcmd); +- else +- pcmd_callback(padapter, pcmd); +- return H2C_SUCCESS; +-} +- +-static u8 write_macreg_hdl(struct _adapter *padapter, u8 *pbuf) +-{ +- void (*pcmd_callback)(struct _adapter *dev, struct cmd_obj *pcmd); +- struct cmd_obj *pcmd = (struct cmd_obj *)pbuf; +- +- /* invoke cmd->callback function */ +- pcmd_callback = cmd_callback[pcmd->cmdcode].callback; +- if (!pcmd_callback) +- r8712_free_cmd_obj(pcmd); +- else +- pcmd_callback(padapter, pcmd); +- return H2C_SUCCESS; +-} +- + static u8 read_bbreg_hdl(struct _adapter *padapter, u8 *pbuf) + { + struct cmd_obj *pcmd = (struct cmd_obj *)pbuf; +@@ -213,14 +185,6 @@ static struct cmd_obj *cmd_hdl_filter(struct _adapter *padapter, + pcmd_r = NULL; + + switch (pcmd->cmdcode) { +- case GEN_CMD_CODE(_Read_MACREG): +- read_macreg_hdl(padapter, (u8 *)pcmd); +- pcmd_r = pcmd; +- break; +- case GEN_CMD_CODE(_Write_MACREG): +- write_macreg_hdl(padapter, (u8 *)pcmd); +- pcmd_r = pcmd; +- break; + case GEN_CMD_CODE(_Read_BBREG): + read_bbreg_hdl(padapter, (u8 *)pcmd); + break; +diff --git a/drivers/thunderbolt/ctl.c b/drivers/thunderbolt/ctl.c +index 0fb5e04191e24..409ee1551a7cf 100644 +--- a/drivers/thunderbolt/ctl.c ++++ b/drivers/thunderbolt/ctl.c +@@ -408,7 +408,7 @@ static void tb_ctl_rx_submit(struct ctl_pkg *pkg) + + static int tb_async_error(const struct ctl_pkg *pkg) + { +- const struct cfg_error_pkg *error = (const struct cfg_error_pkg *)pkg; ++ const struct cfg_error_pkg *error = pkg->buffer; + + if (pkg->frame.eof != TB_CFG_PKG_ERROR) + return false; +diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c +index b89655f585f14..154697be11b0a 100644 +--- a/drivers/tty/n_gsm.c ++++ b/drivers/tty/n_gsm.c +@@ -2753,7 +2753,8 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp, + flags = *fp++; + switch (flags) { + case TTY_NORMAL: +- gsm->receive(gsm, *cp); ++ if (gsm->receive) ++ gsm->receive(gsm, *cp); + break; + case TTY_OVERRUN: + case TTY_BREAK: +diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c +index 4155bd10711da..bf11ffafcad53 100644 +--- a/drivers/tty/serial/fsl_lpuart.c ++++ b/drivers/tty/serial/fsl_lpuart.c +@@ -1381,9 +1381,9 @@ static int lpuart_config_rs485(struct uart_port *port, + * Note: UART is assumed to be active high. + */ + if (rs485->flags & SER_RS485_RTS_ON_SEND) +- modem &= ~UARTMODEM_TXRTSPOL; +- else if (rs485->flags & SER_RS485_RTS_AFTER_SEND) + modem |= UARTMODEM_TXRTSPOL; ++ else if (rs485->flags & SER_RS485_RTS_AFTER_SEND) ++ modem &= ~UARTMODEM_TXRTSPOL; + } + + /* Store the new configuration */ +@@ -2203,6 +2203,7 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, + uart_update_timeout(port, termios->c_cflag, baud); + + /* wait transmit engin complete */ ++ lpuart32_write(&sport->port, 0, UARTMODIR); + lpuart32_wait_bit_set(&sport->port, UARTSTAT, UARTSTAT_TC); + + /* disable transmit and receive */ +diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c +index 6eaf8eb846619..b8f5bc19416d9 100644 +--- a/drivers/tty/vt/vt.c ++++ b/drivers/tty/vt/vt.c +@@ -4662,9 +4662,11 @@ static int con_font_set(struct vc_data *vc, struct console_font_op *op) + console_lock(); + if (vc->vc_mode != KD_TEXT) + rc = -EINVAL; +- else if (vc->vc_sw->con_font_set) ++ else if (vc->vc_sw->con_font_set) { ++ if (vc_is_sel(vc)) ++ clear_selection(); + rc = vc->vc_sw->con_font_set(vc, &font, op->flags); +- else ++ } else + rc = -ENOSYS; + console_unlock(); + kfree(font.data); +@@ -4691,9 +4693,11 @@ static int con_font_default(struct vc_data *vc, struct console_font_op *op) + console_unlock(); + return -EINVAL; + } +- if (vc->vc_sw->con_font_default) ++ if (vc->vc_sw->con_font_default) { ++ if (vc_is_sel(vc)) ++ clear_selection(); + rc = vc->vc_sw->con_font_default(vc, &font, s); +- else ++ } else + rc = -ENOSYS; + console_unlock(); + if (!rc) { +diff --git a/drivers/usb/cdns3/cdns3-gadget.c b/drivers/usb/cdns3/cdns3-gadget.c +index 3f1ce89110776..1802f6818e632 100644 +--- a/drivers/usb/cdns3/cdns3-gadget.c ++++ b/drivers/usb/cdns3/cdns3-gadget.c +@@ -1530,7 +1530,8 @@ static void cdns3_transfer_completed(struct cdns3_device *priv_dev, + TRB_LEN(le32_to_cpu(trb->length)); + + if (priv_req->num_of_trb > 1 && +- le32_to_cpu(trb->control) & TRB_SMM) ++ le32_to_cpu(trb->control) & TRB_SMM && ++ le32_to_cpu(trb->control) & TRB_CHAIN) + transfer_end = true; + + cdns3_ep_inc_deq(priv_ep); +@@ -1690,6 +1691,7 @@ static int cdns3_check_ep_interrupt_proceed(struct cdns3_endpoint *priv_ep) + ep_cfg &= ~EP_CFG_ENABLE; + writel(ep_cfg, &priv_dev->regs->ep_cfg); + priv_ep->flags &= ~EP_QUIRK_ISO_OUT_EN; ++ priv_ep->flags |= EP_UPDATE_EP_TRBADDR; + } + cdns3_transfer_completed(priv_dev, priv_ep); + } else if (!(priv_ep->flags & EP_STALLED) && +diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c +index 7b2e2420ecaea..adc154b691d05 100644 +--- a/drivers/usb/class/cdc-acm.c ++++ b/drivers/usb/class/cdc-acm.c +@@ -1814,6 +1814,9 @@ static const struct usb_device_id acm_ids[] = { + { USB_DEVICE(0x09d8, 0x0320), /* Elatec GmbH TWN3 */ + .driver_info = NO_UNION_NORMAL, /* has misplaced union descriptor */ + }, ++ { USB_DEVICE(0x0c26, 0x0020), /* Icom ICF3400 Serie */ ++ .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */ ++ }, + { USB_DEVICE(0x0ca6, 0xa050), /* Castles VEGA3000 */ + .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */ + }, +diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c +index ac6c5ccfe1cb7..23896c8e018a3 100644 +--- a/drivers/usb/core/hub.c ++++ b/drivers/usb/core/hub.c +@@ -6043,6 +6043,11 @@ re_enumerate_no_bos: + * the reset is over (using their post_reset method). + * + * Return: The same as for usb_reset_and_verify_device(). ++ * However, if a reset is already in progress (for instance, if a ++ * driver doesn't have pre_ or post_reset() callbacks, and while ++ * being unbound or re-bound during the ongoing reset its disconnect() ++ * or probe() routine tries to perform a second, nested reset), the ++ * routine returns -EINPROGRESS. + * + * Note: + * The caller must own the device lock. For example, it's safe to use +@@ -6076,6 +6081,10 @@ int usb_reset_device(struct usb_device *udev) + return -EISDIR; + } + ++ if (udev->reset_in_progress) ++ return -EINPROGRESS; ++ udev->reset_in_progress = 1; ++ + port_dev = hub->ports[udev->portnum - 1]; + + /* +@@ -6140,6 +6149,7 @@ int usb_reset_device(struct usb_device *udev) + + usb_autosuspend_device(udev); + memalloc_noio_restore(noio_flag); ++ udev->reset_in_progress = 0; + return ret; + } + EXPORT_SYMBOL_GPL(usb_reset_device); +diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c +index c331a5128c2c0..265d437ca0f11 100644 +--- a/drivers/usb/dwc2/platform.c ++++ b/drivers/usb/dwc2/platform.c +@@ -154,9 +154,9 @@ static int __dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg) + } else if (hsotg->plat && hsotg->plat->phy_init) { + ret = hsotg->plat->phy_init(pdev, hsotg->plat->phy_type); + } else { +- ret = phy_power_on(hsotg->phy); ++ ret = phy_init(hsotg->phy); + if (ret == 0) +- ret = phy_init(hsotg->phy); ++ ret = phy_power_on(hsotg->phy); + } + + return ret; +@@ -188,9 +188,9 @@ static int __dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg) + } else if (hsotg->plat && hsotg->plat->phy_exit) { + ret = hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type); + } else { +- ret = phy_exit(hsotg->phy); ++ ret = phy_power_off(hsotg->phy); + if (ret == 0) +- ret = phy_power_off(hsotg->phy); ++ ret = phy_exit(hsotg->phy); + } + if (ret) + return ret; +diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c +index cfac5503aa662..9c24cf46b9a08 100644 +--- a/drivers/usb/dwc3/core.c ++++ b/drivers/usb/dwc3/core.c +@@ -731,15 +731,16 @@ static void dwc3_core_exit(struct dwc3 *dwc) + { + dwc3_event_buffers_cleanup(dwc); + ++ usb_phy_set_suspend(dwc->usb2_phy, 1); ++ usb_phy_set_suspend(dwc->usb3_phy, 1); ++ phy_power_off(dwc->usb2_generic_phy); ++ phy_power_off(dwc->usb3_generic_phy); ++ + usb_phy_shutdown(dwc->usb2_phy); + usb_phy_shutdown(dwc->usb3_phy); + phy_exit(dwc->usb2_generic_phy); + phy_exit(dwc->usb3_generic_phy); + +- usb_phy_set_suspend(dwc->usb2_phy, 1); +- usb_phy_set_suspend(dwc->usb3_phy, 1); +- phy_power_off(dwc->usb2_generic_phy); +- phy_power_off(dwc->usb3_generic_phy); + clk_bulk_disable_unprepare(dwc->num_clks, dwc->clks); + reset_control_assert(dwc->reset); + } +@@ -1662,16 +1663,16 @@ err5: + dwc3_debugfs_exit(dwc); + dwc3_event_buffers_cleanup(dwc); + +- usb_phy_shutdown(dwc->usb2_phy); +- usb_phy_shutdown(dwc->usb3_phy); +- phy_exit(dwc->usb2_generic_phy); +- phy_exit(dwc->usb3_generic_phy); +- + usb_phy_set_suspend(dwc->usb2_phy, 1); + usb_phy_set_suspend(dwc->usb3_phy, 1); + phy_power_off(dwc->usb2_generic_phy); + phy_power_off(dwc->usb3_generic_phy); + ++ usb_phy_shutdown(dwc->usb2_phy); ++ usb_phy_shutdown(dwc->usb3_phy); ++ phy_exit(dwc->usb2_generic_phy); ++ phy_exit(dwc->usb3_generic_phy); ++ + dwc3_ulpi_exit(dwc); + + err4: +diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c +index 9c8887615701f..c52f7b5b5ec00 100644 +--- a/drivers/usb/dwc3/dwc3-pci.c ++++ b/drivers/usb/dwc3/dwc3-pci.c +@@ -43,6 +43,7 @@ + #define PCI_DEVICE_ID_INTEL_ADLP 0x51ee + #define PCI_DEVICE_ID_INTEL_ADLM 0x54ee + #define PCI_DEVICE_ID_INTEL_ADLS 0x7ae1 ++#define PCI_DEVICE_ID_INTEL_RPL 0x460e + #define PCI_DEVICE_ID_INTEL_RPLS 0x7a61 + #define PCI_DEVICE_ID_INTEL_MTLP 0x7ec1 + #define PCI_DEVICE_ID_INTEL_MTL 0x7e7e +@@ -420,6 +421,9 @@ static const struct pci_device_id dwc3_pci_id_table[] = { + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADLS), + (kernel_ulong_t) &dwc3_pci_intel_swnode, }, + ++ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_RPL), ++ (kernel_ulong_t) &dwc3_pci_intel_swnode, }, ++ + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_RPLS), + (kernel_ulong_t) &dwc3_pci_intel_swnode, }, + +diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c +index 873bf5041117f..d0352daab0128 100644 +--- a/drivers/usb/dwc3/dwc3-qcom.c ++++ b/drivers/usb/dwc3/dwc3-qcom.c +@@ -296,6 +296,14 @@ static void dwc3_qcom_interconnect_exit(struct dwc3_qcom *qcom) + icc_put(qcom->icc_path_apps); + } + ++/* Only usable in contexts where the role can not change. */ ++static bool dwc3_qcom_is_host(struct dwc3_qcom *qcom) ++{ ++ struct dwc3 *dwc = platform_get_drvdata(qcom->dwc3); ++ ++ return dwc->xhci; ++} ++ + static void dwc3_qcom_disable_interrupts(struct dwc3_qcom *qcom) + { + if (qcom->hs_phy_irq) { +@@ -411,7 +419,11 @@ static irqreturn_t qcom_dwc3_resume_irq(int irq, void *data) + if (qcom->pm_suspended) + return IRQ_HANDLED; + +- if (dwc->xhci) ++ /* ++ * This is safe as role switching is done from a freezable workqueue ++ * and the wakeup interrupts are disabled as part of resume. ++ */ ++ if (dwc3_qcom_is_host(qcom)) + pm_runtime_resume(&dwc->xhci->dev); + + return IRQ_HANDLED; +diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c +index f29a264635aa1..85165a972076d 100644 +--- a/drivers/usb/dwc3/host.c ++++ b/drivers/usb/dwc3/host.c +@@ -10,8 +10,13 @@ + #include <linux/acpi.h> + #include <linux/platform_device.h> + ++#include "../host/xhci-plat.h" + #include "core.h" + ++static const struct xhci_plat_priv dwc3_xhci_plat_priv = { ++ .quirks = XHCI_SKIP_PHY_INIT, ++}; ++ + static int dwc3_host_get_irq(struct dwc3 *dwc) + { + struct platform_device *dwc3_pdev = to_platform_device(dwc->dev); +@@ -87,6 +92,11 @@ int dwc3_host_init(struct dwc3 *dwc) + goto err; + } + ++ ret = platform_device_add_data(xhci, &dwc3_xhci_plat_priv, ++ sizeof(dwc3_xhci_plat_priv)); ++ if (ret) ++ goto err; ++ + memset(props, 0, sizeof(struct property_entry) * ARRAY_SIZE(props)); + + if (dwc->usb3_lpm_capable) +@@ -130,4 +140,5 @@ err: + void dwc3_host_exit(struct dwc3 *dwc) + { + platform_device_unregister(dwc->xhci); ++ dwc->xhci = NULL; + } +diff --git a/drivers/usb/gadget/function/storage_common.c b/drivers/usb/gadget/function/storage_common.c +index b859a158a4140..e122050eebaf1 100644 +--- a/drivers/usb/gadget/function/storage_common.c ++++ b/drivers/usb/gadget/function/storage_common.c +@@ -294,8 +294,10 @@ EXPORT_SYMBOL_GPL(fsg_lun_fsync_sub); + void store_cdrom_address(u8 *dest, int msf, u32 addr) + { + if (msf) { +- /* Convert to Minutes-Seconds-Frames */ +- addr >>= 2; /* Convert to 2048-byte frames */ ++ /* ++ * Convert to Minutes-Seconds-Frames. ++ * Sector size is already set to 2048 bytes. ++ */ + addr += 2*75; /* Lead-in occupies 2 seconds */ + dest[3] = addr % 75; /* Frames */ + addr /= 75; +diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c +index fc322a9526c8c..b9754784161d7 100644 +--- a/drivers/usb/host/xhci-hub.c ++++ b/drivers/usb/host/xhci-hub.c +@@ -652,7 +652,7 @@ struct xhci_hub *xhci_get_rhub(struct usb_hcd *hcd) + * It will release and re-aquire the lock while calling ACPI + * method. + */ +-void xhci_set_port_power(struct xhci_hcd *xhci, struct usb_hcd *hcd, ++static void xhci_set_port_power(struct xhci_hcd *xhci, struct usb_hcd *hcd, + u16 index, bool on, unsigned long *flags) + __must_hold(&xhci->lock) + { +@@ -1647,6 +1647,17 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) + + status = bus_state->resuming_ports; + ++ /* ++ * SS devices are only visible to roothub after link training completes. ++ * Keep polling roothubs for a grace period after xHC start ++ */ ++ if (xhci->run_graceperiod) { ++ if (time_before(jiffies, xhci->run_graceperiod)) ++ status = 1; ++ else ++ xhci->run_graceperiod = 0; ++ } ++ + mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC | PORT_WRC | PORT_CEC; + + /* For each port, did anything change? If so, set that bit in buf. */ +diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c +index f91a304320563..9d8094afcc8bc 100644 +--- a/drivers/usb/host/xhci-mtk-sch.c ++++ b/drivers/usb/host/xhci-mtk-sch.c +@@ -476,7 +476,6 @@ static int check_fs_bus_bw(struct mu3h_sch_ep_info *sch_ep, int offset) + + static int check_sch_tt(struct mu3h_sch_ep_info *sch_ep, u32 offset) + { +- u32 extra_cs_count; + u32 start_ss, last_ss; + u32 start_cs, last_cs; + +@@ -512,18 +511,12 @@ static int check_sch_tt(struct mu3h_sch_ep_info *sch_ep, u32 offset) + if (last_cs > 7) + return -ESCH_CS_OVERFLOW; + +- if (sch_ep->ep_type == ISOC_IN_EP) +- extra_cs_count = (last_cs == 7) ? 1 : 2; +- else /* ep_type : INTR IN / INTR OUT */ +- extra_cs_count = 1; +- +- cs_count += extra_cs_count; + if (cs_count > 7) + cs_count = 7; /* HW limit */ + + sch_ep->cs_count = cs_count; +- /* one for ss, the other for idle */ +- sch_ep->num_budget_microframes = cs_count + 2; ++ /* ss, idle are ignored */ ++ sch_ep->num_budget_microframes = cs_count; + + /* + * if interval=1, maxp >752, num_budge_micoframe is larger +@@ -822,8 +815,8 @@ int xhci_mtk_drop_ep(struct usb_hcd *hcd, struct usb_device *udev, + if (ret) + return ret; + +- if (ep->hcpriv) +- drop_ep_quirk(hcd, udev, ep); ++ /* needn't check @ep->hcpriv, xhci_endpoint_disable set it NULL */ ++ drop_ep_quirk(hcd, udev, ep); + + return 0; + } +diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c +index d76c10f9ad807..3cac7e40456eb 100644 +--- a/drivers/usb/host/xhci.c ++++ b/drivers/usb/host/xhci.c +@@ -148,9 +148,11 @@ int xhci_start(struct xhci_hcd *xhci) + xhci_err(xhci, "Host took too long to start, " + "waited %u microseconds.\n", + XHCI_MAX_HALT_USEC); +- if (!ret) ++ if (!ret) { + /* clear state flags. Including dying, halted or removing */ + xhci->xhc_state = 0; ++ xhci->run_graceperiod = jiffies + msecs_to_jiffies(500); ++ } + + return ret; + } +@@ -776,8 +778,6 @@ static void xhci_stop(struct usb_hcd *hcd) + void xhci_shutdown(struct usb_hcd *hcd) + { + struct xhci_hcd *xhci = hcd_to_xhci(hcd); +- unsigned long flags; +- int i; + + if (xhci->quirks & XHCI_SPURIOUS_REBOOT) + usb_disable_xhci_ports(to_pci_dev(hcd->self.sysdev)); +@@ -793,21 +793,12 @@ void xhci_shutdown(struct usb_hcd *hcd) + del_timer_sync(&xhci->shared_hcd->rh_timer); + } + +- spin_lock_irqsave(&xhci->lock, flags); ++ spin_lock_irq(&xhci->lock); + xhci_halt(xhci); +- +- /* Power off USB2 ports*/ +- for (i = 0; i < xhci->usb2_rhub.num_ports; i++) +- xhci_set_port_power(xhci, xhci->main_hcd, i, false, &flags); +- +- /* Power off USB3 ports*/ +- for (i = 0; i < xhci->usb3_rhub.num_ports; i++) +- xhci_set_port_power(xhci, xhci->shared_hcd, i, false, &flags); +- + /* Workaround for spurious wakeups at shutdown with HSW */ + if (xhci->quirks & XHCI_SPURIOUS_WAKEUP) + xhci_reset(xhci, XHCI_RESET_SHORT_USEC); +- spin_unlock_irqrestore(&xhci->lock, flags); ++ spin_unlock_irq(&xhci->lock); + + xhci_cleanup_msix(xhci); + +diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h +index 101f1956a96ca..10a4230d95c37 100644 +--- a/drivers/usb/host/xhci.h ++++ b/drivers/usb/host/xhci.h +@@ -1830,7 +1830,7 @@ struct xhci_hcd { + + /* Host controller watchdog timer structures */ + unsigned int xhc_state; +- ++ unsigned long run_graceperiod; + u32 command; + struct s3_save s3; + /* Host controller is dying - not responding to commands. "I'm not dead yet!" +@@ -2174,8 +2174,6 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, + int xhci_hub_status_data(struct usb_hcd *hcd, char *buf); + int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1); + struct xhci_hub *xhci_get_rhub(struct usb_hcd *hcd); +-void xhci_set_port_power(struct xhci_hcd *xhci, struct usb_hcd *hcd, u16 index, +- bool on, unsigned long *flags); + + void xhci_hc_died(struct xhci_hcd *xhci); + +diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig +index 4d61df6a9b5c8..70693cae83efb 100644 +--- a/drivers/usb/musb/Kconfig ++++ b/drivers/usb/musb/Kconfig +@@ -86,7 +86,7 @@ config USB_MUSB_TUSB6010 + tristate "TUSB6010" + depends on HAS_IOMEM + depends on ARCH_OMAP2PLUS || COMPILE_TEST +- depends on NOP_USB_XCEIV = USB_MUSB_HDRC # both built-in or both modules ++ depends on NOP_USB_XCEIV!=m || USB_MUSB_HDRC=m + + config USB_MUSB_OMAP2PLUS + tristate "OMAP2430 and onwards" +diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c +index b5a1864e9cfdc..752daa952abd6 100644 +--- a/drivers/usb/serial/ch341.c ++++ b/drivers/usb/serial/ch341.c +@@ -97,7 +97,10 @@ struct ch341_private { + u8 mcr; + u8 msr; + u8 lcr; ++ + unsigned long quirks; ++ u8 version; ++ + unsigned long break_end; + }; + +@@ -256,8 +259,12 @@ static int ch341_set_baudrate_lcr(struct usb_device *dev, + /* + * CH341A buffers data until a full endpoint-size packet (32 bytes) + * has been received unless bit 7 is set. ++ * ++ * At least one device with version 0x27 appears to have this bit ++ * inverted. + */ +- val |= BIT(7); ++ if (priv->version > 0x27) ++ val |= BIT(7); + + r = ch341_control_out(dev, CH341_REQ_WRITE_REG, + CH341_REG_DIVISOR << 8 | CH341_REG_PRESCALER, +@@ -271,6 +278,9 @@ static int ch341_set_baudrate_lcr(struct usb_device *dev, + * (stop bits, parity and word length). Version 0x30 and above use + * CH341_REG_LCR only and CH341_REG_LCR2 is always set to zero. + */ ++ if (priv->version < 0x30) ++ return 0; ++ + r = ch341_control_out(dev, CH341_REQ_WRITE_REG, + CH341_REG_LCR2 << 8 | CH341_REG_LCR, lcr); + if (r) +@@ -323,7 +333,9 @@ static int ch341_configure(struct usb_device *dev, struct ch341_private *priv) + r = ch341_control_in(dev, CH341_REQ_READ_VERSION, 0, 0, buffer, size); + if (r < 0) + goto out; +- dev_dbg(&dev->dev, "Chip version: 0x%02x\n", buffer[0]); ++ ++ priv->version = buffer[0]; ++ dev_dbg(&dev->dev, "Chip version: 0x%02x\n", priv->version); + + r = ch341_control_out(dev, CH341_REQ_SERIAL_INIT, 0, 0); + if (r < 0) +diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c +index bd006e1712ccb..a2126b07e854a 100644 +--- a/drivers/usb/serial/cp210x.c ++++ b/drivers/usb/serial/cp210x.c +@@ -130,6 +130,7 @@ static const struct usb_device_id id_table[] = { + { USB_DEVICE(0x10C4, 0x83AA) }, /* Mark-10 Digital Force Gauge */ + { USB_DEVICE(0x10C4, 0x83D8) }, /* DekTec DTA Plus VHF/UHF Booster/Attenuator */ + { USB_DEVICE(0x10C4, 0x8411) }, /* Kyocera GPS Module */ ++ { USB_DEVICE(0x10C4, 0x8414) }, /* Decagon USB Cable Adapter */ + { USB_DEVICE(0x10C4, 0x8418) }, /* IRZ Automation Teleport SG-10 GSM/GPRS Modem */ + { USB_DEVICE(0x10C4, 0x846E) }, /* BEI USB Sensor Interface (VCP) */ + { USB_DEVICE(0x10C4, 0x8470) }, /* Juniper Networks BX Series System Console */ +diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c +index e2a8c33f0cae9..a2ecb3b5d13e6 100644 +--- a/drivers/usb/serial/ftdi_sio.c ++++ b/drivers/usb/serial/ftdi_sio.c +@@ -1045,6 +1045,8 @@ static const struct usb_device_id id_table_combined[] = { + /* IDS GmbH devices */ + { USB_DEVICE(IDS_VID, IDS_SI31A_PID) }, + { USB_DEVICE(IDS_VID, IDS_CM31A_PID) }, ++ /* Omron devices */ ++ { USB_DEVICE(OMRON_VID, OMRON_CS1W_CIF31_PID) }, + /* U-Blox devices */ + { USB_DEVICE(UBLOX_VID, UBLOX_C099F9P_ZED_PID) }, + { USB_DEVICE(UBLOX_VID, UBLOX_C099F9P_ODIN_PID) }, +diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h +index 4e92c165c86bf..31c8ccabbbb78 100644 +--- a/drivers/usb/serial/ftdi_sio_ids.h ++++ b/drivers/usb/serial/ftdi_sio_ids.h +@@ -661,6 +661,12 @@ + #define INFINEON_TRIBOARD_TC1798_PID 0x0028 /* DAS JTAG TriBoard TC1798 V1.0 */ + #define INFINEON_TRIBOARD_TC2X7_PID 0x0043 /* DAS JTAG TriBoard TC2X7 V1.0 */ + ++/* ++ * Omron corporation (https://www.omron.com) ++ */ ++ #define OMRON_VID 0x0590 ++ #define OMRON_CS1W_CIF31_PID 0x00b2 ++ + /* + * Acton Research Corp. + */ +diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c +index de59fa919540a..a5e8374a8d710 100644 +--- a/drivers/usb/serial/option.c ++++ b/drivers/usb/serial/option.c +@@ -253,6 +253,7 @@ static void option_instat_callback(struct urb *urb); + #define QUECTEL_PRODUCT_BG96 0x0296 + #define QUECTEL_PRODUCT_EP06 0x0306 + #define QUECTEL_PRODUCT_EM05G 0x030a ++#define QUECTEL_PRODUCT_EM060K 0x030b + #define QUECTEL_PRODUCT_EM12 0x0512 + #define QUECTEL_PRODUCT_RM500Q 0x0800 + #define QUECTEL_PRODUCT_EC200S_CN 0x6002 +@@ -438,6 +439,8 @@ static void option_instat_callback(struct urb *urb); + #define CINTERION_PRODUCT_MV31_2_RMNET 0x00b9 + #define CINTERION_PRODUCT_MV32_WA 0x00f1 + #define CINTERION_PRODUCT_MV32_WB 0x00f2 ++#define CINTERION_PRODUCT_MV32_WA_RMNET 0x00f3 ++#define CINTERION_PRODUCT_MV32_WB_RMNET 0x00f4 + + /* Olivetti products */ + #define OLIVETTI_VENDOR_ID 0x0b3c +@@ -573,6 +576,10 @@ static void option_instat_callback(struct urb *urb); + #define WETELECOM_PRODUCT_6802 0x6802 + #define WETELECOM_PRODUCT_WMD300 0x6803 + ++/* OPPO products */ ++#define OPPO_VENDOR_ID 0x22d9 ++#define OPPO_PRODUCT_R11 0x276c ++ + + /* Device flags */ + +@@ -1138,6 +1145,9 @@ static const struct usb_device_id option_ids[] = { + { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06, 0xff, 0, 0) }, + { USB_DEVICE_INTERFACE_CLASS(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM05G, 0xff), + .driver_info = RSVD(6) | ZLP }, ++ { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM060K, 0xff, 0x00, 0x40) }, ++ { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM060K, 0xff, 0xff, 0x30) }, ++ { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM060K, 0xff, 0xff, 0x40) }, + { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM12, 0xff, 0xff, 0xff), + .driver_info = RSVD(1) | RSVD(2) | RSVD(3) | RSVD(4) | NUMEP2 }, + { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM12, 0xff, 0, 0) }, +@@ -1993,8 +2003,12 @@ static const struct usb_device_id option_ids[] = { + .driver_info = RSVD(0)}, + { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_MV32_WA, 0xff), + .driver_info = RSVD(3)}, ++ { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_MV32_WA_RMNET, 0xff), ++ .driver_info = RSVD(0) }, + { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_MV32_WB, 0xff), + .driver_info = RSVD(3)}, ++ { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_MV32_WB_RMNET, 0xff), ++ .driver_info = RSVD(0) }, + { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100), + .driver_info = RSVD(4) }, + { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD120), +@@ -2155,6 +2169,7 @@ static const struct usb_device_id option_ids[] = { + { USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1404, 0xff) }, /* GosunCn GM500 RNDIS */ + { USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1405, 0xff) }, /* GosunCn GM500 MBIM */ + { USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1406, 0xff) }, /* GosunCn GM500 ECM/NCM */ ++ { USB_DEVICE_AND_INTERFACE_INFO(OPPO_VENDOR_ID, OPPO_PRODUCT_R11, 0xff, 0xff, 0x30) }, + { } /* Terminating entry */ + }; + MODULE_DEVICE_TABLE(usb, option_ids); +diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h +index 1a05e3dcfec8a..4993227ab2930 100644 +--- a/drivers/usb/storage/unusual_devs.h ++++ b/drivers/usb/storage/unusual_devs.h +@@ -2294,6 +2294,13 @@ UNUSUAL_DEV( 0x1e74, 0x4621, 0x0000, 0x0000, + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_BULK_IGNORE_TAG | US_FL_MAX_SECTORS_64 ), + ++/* Reported by Witold Lipieta <witold.lipieta@thaumatec.com> */ ++UNUSUAL_DEV( 0x1fc9, 0x0117, 0x0100, 0x0100, ++ "NXP Semiconductors", ++ "PN7462AU", ++ USB_SC_DEVICE, USB_PR_DEVICE, NULL, ++ US_FL_IGNORE_RESIDUE ), ++ + /* Supplied with some Castlewood ORB removable drives */ + UNUSUAL_DEV( 0x2027, 0xa001, 0x0000, 0x9999, + "Double-H Technology", +diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c +index b7f094435b00a..998c1e3e318e1 100644 +--- a/drivers/usb/typec/altmodes/displayport.c ++++ b/drivers/usb/typec/altmodes/displayport.c +@@ -88,8 +88,8 @@ static int dp_altmode_configure(struct dp_altmode *dp, u8 con) + case DP_STATUS_CON_UFP_D: + case DP_STATUS_CON_BOTH: /* NOTE: First acting as DP source */ + conf |= DP_CONF_UFP_U_AS_UFP_D; +- pin_assign = DP_CAP_DFP_D_PIN_ASSIGN(dp->alt->vdo) & +- DP_CAP_UFP_D_PIN_ASSIGN(dp->port->vdo); ++ pin_assign = DP_CAP_PIN_ASSIGN_UFP_D(dp->alt->vdo) & ++ DP_CAP_PIN_ASSIGN_DFP_D(dp->port->vdo); + break; + default: + break; +diff --git a/drivers/usb/typec/mux/intel_pmc_mux.c b/drivers/usb/typec/mux/intel_pmc_mux.c +index 2cdd22130834e..5daec9d79e94f 100644 +--- a/drivers/usb/typec/mux/intel_pmc_mux.c ++++ b/drivers/usb/typec/mux/intel_pmc_mux.c +@@ -554,9 +554,11 @@ err_unregister_switch: + + static int is_memory(struct acpi_resource *res, void *data) + { +- struct resource r; ++ struct resource_win win = {}; ++ struct resource *r = &win.res; + +- return !acpi_dev_resource_memory(res, &r); ++ return !(acpi_dev_resource_memory(res, r) || ++ acpi_dev_resource_address_space(res, &win)); + } + + /* IOM ACPI IDs and IOM_PORT_STATUS_OFFSET */ +@@ -566,6 +568,9 @@ static const struct acpi_device_id iom_acpi_ids[] = { + + /* AlderLake */ + { "INTC1079", 0x160, }, ++ ++ /* Meteor Lake */ ++ { "INTC107A", 0x160, }, + {} + }; + +diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c +index 5fce795b69c7f..33aadc0a29ea8 100644 +--- a/drivers/usb/typec/tcpm/tcpm.c ++++ b/drivers/usb/typec/tcpm/tcpm.c +@@ -6213,6 +6213,13 @@ static int tcpm_psy_set_prop(struct power_supply *psy, + struct tcpm_port *port = power_supply_get_drvdata(psy); + int ret; + ++ /* ++ * All the properties below are related to USB PD. The check needs to be ++ * property specific when a non-pd related property is added. ++ */ ++ if (!port->pd_supported) ++ return -EOPNOTSUPP; ++ + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + ret = tcpm_psy_set_online(port, val); +diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c +index 5c83d41766c85..0a2d24d6ac6f7 100644 +--- a/drivers/xen/grant-table.c ++++ b/drivers/xen/grant-table.c +@@ -981,6 +981,9 @@ int gnttab_dma_alloc_pages(struct gnttab_dma_alloc_args *args) + size_t size; + int i, ret; + ++ if (args->nr_pages < 0 || args->nr_pages > (INT_MAX >> PAGE_SHIFT)) ++ return -ENOMEM; ++ + size = args->nr_pages << PAGE_SHIFT; + if (args->coherent) + args->vaddr = dma_alloc_coherent(args->dev, size, +diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c +index 49ba3617db593..a423d14035391 100644 +--- a/fs/cifs/smb2pdu.c ++++ b/fs/cifs/smb2pdu.c +@@ -933,16 +933,17 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) + } else if (rc != 0) + goto neg_exit; + ++ rc = -EIO; + if (strcmp(server->vals->version_string, + SMB3ANY_VERSION_STRING) == 0) { + if (rsp->DialectRevision == cpu_to_le16(SMB20_PROT_ID)) { + cifs_server_dbg(VFS, + "SMB2 dialect returned but not requested\n"); +- return -EIO; ++ goto neg_exit; + } else if (rsp->DialectRevision == cpu_to_le16(SMB21_PROT_ID)) { + cifs_server_dbg(VFS, + "SMB2.1 dialect returned but not requested\n"); +- return -EIO; ++ goto neg_exit; + } else if (rsp->DialectRevision == cpu_to_le16(SMB311_PROT_ID)) { + /* ops set to 3.0 by default for default so update */ + server->ops = &smb311_operations; +@@ -953,7 +954,7 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) + if (rsp->DialectRevision == cpu_to_le16(SMB20_PROT_ID)) { + cifs_server_dbg(VFS, + "SMB2 dialect returned but not requested\n"); +- return -EIO; ++ goto neg_exit; + } else if (rsp->DialectRevision == cpu_to_le16(SMB21_PROT_ID)) { + /* ops set to 3.0 by default for default so update */ + server->ops = &smb21_operations; +@@ -967,7 +968,7 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) + /* if requested single dialect ensure returned dialect matched */ + cifs_server_dbg(VFS, "Invalid 0x%x dialect returned: not requested\n", + le16_to_cpu(rsp->DialectRevision)); +- return -EIO; ++ goto neg_exit; + } + + cifs_dbg(FYI, "mode 0x%x\n", rsp->SecurityMode); +@@ -985,9 +986,10 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) + else { + cifs_server_dbg(VFS, "Invalid dialect returned by server 0x%x\n", + le16_to_cpu(rsp->DialectRevision)); +- rc = -EIO; + goto neg_exit; + } ++ ++ rc = 0; + server->dialect = le16_to_cpu(rsp->DialectRevision); + + /* +diff --git a/include/linux/platform_data/x86/pmc_atom.h b/include/linux/platform_data/x86/pmc_atom.h +index 022bcea9edec5..99a9b09dc839d 100644 +--- a/include/linux/platform_data/x86/pmc_atom.h ++++ b/include/linux/platform_data/x86/pmc_atom.h +@@ -7,6 +7,8 @@ + #ifndef PMC_ATOM_H + #define PMC_ATOM_H + ++#include <linux/bits.h> ++ + /* ValleyView Power Control Unit PCI Device ID */ + #define PCI_DEVICE_ID_VLV_PMC 0x0F1C + /* CherryTrail Power Control Unit PCI Device ID */ +@@ -139,9 +141,9 @@ + #define ACPI_MMIO_REG_LEN 0x100 + + #define PM1_CNT 0x4 +-#define SLEEP_TYPE_MASK 0xFFFFECFF ++#define SLEEP_TYPE_MASK GENMASK(12, 10) + #define SLEEP_TYPE_S5 0x1C00 +-#define SLEEP_ENABLE 0x2000 ++#define SLEEP_ENABLE BIT(13) + + extern int pmc_atom_read(int offset, u32 *value); + extern int pmc_atom_write(int offset, u32 value); +diff --git a/include/linux/usb.h b/include/linux/usb.h +index 7ccaa76a9a968..da1329b85329b 100644 +--- a/include/linux/usb.h ++++ b/include/linux/usb.h +@@ -575,6 +575,7 @@ struct usb3_lpm_parameters { + * @devaddr: device address, XHCI: assigned by HW, others: same as devnum + * @can_submit: URBs may be submitted + * @persist_enabled: USB_PERSIST enabled for this device ++ * @reset_in_progress: the device is being reset + * @have_langid: whether string_langid is valid + * @authorized: policy has said we can use it; + * (user space) policy determines if we authorize this device to be +@@ -661,6 +662,7 @@ struct usb_device { + + unsigned can_submit:1; + unsigned persist_enabled:1; ++ unsigned reset_in_progress:1; + unsigned have_langid:1; + unsigned authorized:1; + unsigned authenticated:1; +diff --git a/include/linux/usb/typec_dp.h b/include/linux/usb/typec_dp.h +index cfb916cccd316..8d09c2f0a9b80 100644 +--- a/include/linux/usb/typec_dp.h ++++ b/include/linux/usb/typec_dp.h +@@ -73,6 +73,11 @@ enum { + #define DP_CAP_USB BIT(7) + #define DP_CAP_DFP_D_PIN_ASSIGN(_cap_) (((_cap_) & GENMASK(15, 8)) >> 8) + #define DP_CAP_UFP_D_PIN_ASSIGN(_cap_) (((_cap_) & GENMASK(23, 16)) >> 16) ++/* Get pin assignment taking plug & receptacle into consideration */ ++#define DP_CAP_PIN_ASSIGN_UFP_D(_cap_) ((_cap_ & DP_CAP_RECEPTACLE) ? \ ++ DP_CAP_UFP_D_PIN_ASSIGN(_cap_) : DP_CAP_DFP_D_PIN_ASSIGN(_cap_)) ++#define DP_CAP_PIN_ASSIGN_DFP_D(_cap_) ((_cap_ & DP_CAP_RECEPTACLE) ? \ ++ DP_CAP_DFP_D_PIN_ASSIGN(_cap_) : DP_CAP_UFP_D_PIN_ASSIGN(_cap_)) + + /* DisplayPort Status Update VDO bits */ + #define DP_STATUS_CONNECTION(_status_) ((_status_) & 3) +diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c +index 565e4c59db660..eb3e787a3a977 100644 +--- a/kernel/bpf/cgroup.c ++++ b/kernel/bpf/cgroup.c +@@ -709,8 +709,10 @@ static void purge_effective_progs(struct cgroup *cgrp, struct bpf_prog *prog, + pos++; + } + } ++ ++ /* no link or prog match, skip the cgroup of this layer */ ++ continue; + found: +- BUG_ON(!cg); + progs = rcu_dereference_protected( + desc->bpf.effective[atype], + lockdep_is_held(&cgroup_mutex)); +diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c +index 48e02a725563f..99ce46f518893 100644 +--- a/kernel/bpf/syscall.c ++++ b/kernel/bpf/syscall.c +@@ -4785,7 +4785,7 @@ syscall_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) + { + switch (func_id) { + case BPF_FUNC_sys_bpf: +- return &bpf_sys_bpf_proto; ++ return !perfmon_capable() ? NULL : &bpf_sys_bpf_proto; + case BPF_FUNC_btf_find_by_name_kind: + return &bpf_btf_find_by_name_kind_proto; + case BPF_FUNC_sys_close: +diff --git a/mm/pagewalk.c b/mm/pagewalk.c +index 9b3db11a4d1db..fa7a3d21a7518 100644 +--- a/mm/pagewalk.c ++++ b/mm/pagewalk.c +@@ -110,7 +110,7 @@ static int walk_pmd_range(pud_t *pud, unsigned long addr, unsigned long end, + do { + again: + next = pmd_addr_end(addr, end); +- if (pmd_none(*pmd) || (!walk->vma && !walk->no_vma)) { ++ if (pmd_none(*pmd)) { + if (ops->pte_hole) + err = ops->pte_hole(addr, next, depth, walk); + if (err) +@@ -171,7 +171,7 @@ static int walk_pud_range(p4d_t *p4d, unsigned long addr, unsigned long end, + do { + again: + next = pud_addr_end(addr, end); +- if (pud_none(*pud) || (!walk->vma && !walk->no_vma)) { ++ if (pud_none(*pud)) { + if (ops->pte_hole) + err = ops->pte_hole(addr, next, depth, walk); + if (err) +@@ -366,19 +366,19 @@ static int __walk_page_range(unsigned long start, unsigned long end, + struct vm_area_struct *vma = walk->vma; + const struct mm_walk_ops *ops = walk->ops; + +- if (vma && ops->pre_vma) { ++ if (ops->pre_vma) { + err = ops->pre_vma(start, end, walk); + if (err) + return err; + } + +- if (vma && is_vm_hugetlb_page(vma)) { ++ if (is_vm_hugetlb_page(vma)) { + if (ops->hugetlb_entry) + err = walk_hugetlb_range(start, end, walk); + } else + err = walk_pgd_range(start, end, walk); + +- if (vma && ops->post_vma) ++ if (ops->post_vma) + ops->post_vma(walk); + + return err; +@@ -450,9 +450,13 @@ int walk_page_range(struct mm_struct *mm, unsigned long start, + if (!vma) { /* after the last vma */ + walk.vma = NULL; + next = end; ++ if (ops->pte_hole) ++ err = ops->pte_hole(start, next, -1, &walk); + } else if (start < vma->vm_start) { /* outside vma */ + walk.vma = NULL; + next = min(end, vma->vm_start); ++ if (ops->pte_hole) ++ err = ops->pte_hole(start, next, -1, &walk); + } else { /* inside vma */ + walk.vma = vma; + next = min(end, vma->vm_end); +@@ -470,9 +474,8 @@ int walk_page_range(struct mm_struct *mm, unsigned long start, + } + if (err < 0) + break; +- } +- if (walk.vma || walk.ops->pte_hole) + err = __walk_page_range(start, next, &walk); ++ } + if (err) + break; + } while (start = next, start < end); +@@ -501,9 +504,9 @@ int walk_page_range_novma(struct mm_struct *mm, unsigned long start, + if (start >= end || !walk.mm) + return -EINVAL; + +- mmap_assert_locked(walk.mm); ++ mmap_assert_write_locked(walk.mm); + +- return __walk_page_range(start, end, &walk); ++ return walk_pgd_range(start, end, &walk); + } + + int walk_page_vma(struct vm_area_struct *vma, const struct mm_walk_ops *ops, +diff --git a/mm/ptdump.c b/mm/ptdump.c +index da751448d0e4e..f84ea700662fc 100644 +--- a/mm/ptdump.c ++++ b/mm/ptdump.c +@@ -144,13 +144,13 @@ void ptdump_walk_pgd(struct ptdump_state *st, struct mm_struct *mm, pgd_t *pgd) + { + const struct ptdump_range *range = st->range; + +- mmap_read_lock(mm); ++ mmap_write_lock(mm); + while (range->start != range->end) { + walk_page_range_novma(mm, range->start, range->end, + &ptdump_ops, pgd, st); + range++; + } +- mmap_read_unlock(mm); ++ mmap_write_unlock(mm); + + /* Flush out the last page */ + st->note_page(st, 0, -1, 0); +diff --git a/net/core/skmsg.c b/net/core/skmsg.c +index 4ddcfac344984..054073c7cbb95 100644 +--- a/net/core/skmsg.c ++++ b/net/core/skmsg.c +@@ -462,7 +462,7 @@ int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, + + if (copied == len) + break; +- } while (!sg_is_last(sge)); ++ } while ((i != msg_rx->sg.end) && !sg_is_last(sge)); + + if (unlikely(peek)) { + msg_rx = sk_psock_next_msg(psock, msg_rx); +@@ -472,7 +472,7 @@ int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, + } + + msg_rx->sg.start = i; +- if (!sge->length && sg_is_last(sge)) { ++ if (!sge->length && (i == msg_rx->sg.end || sg_is_last(sge))) { + msg_rx = sk_psock_dequeue_msg(psock); + kfree_sk_msg(msg_rx); + } +diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c +index 1eb7795edb9dc..1452bb72b7d9c 100644 +--- a/net/ipv4/fib_frontend.c ++++ b/net/ipv4/fib_frontend.c +@@ -389,7 +389,7 @@ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, + dev_match = dev_match || (res.type == RTN_LOCAL && + dev == net->loopback_dev); + if (dev_match) { +- ret = FIB_RES_NHC(res)->nhc_scope >= RT_SCOPE_HOST; ++ ret = FIB_RES_NHC(res)->nhc_scope >= RT_SCOPE_LINK; + return ret; + } + if (no_addr) +@@ -401,7 +401,7 @@ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, + ret = 0; + if (fib_lookup(net, &fl4, &res, FIB_LOOKUP_IGNORE_LINKSTATE) == 0) { + if (res.type == RTN_UNICAST) +- ret = FIB_RES_NHC(res)->nhc_scope >= RT_SCOPE_HOST; ++ ret = FIB_RES_NHC(res)->nhc_scope >= RT_SCOPE_LINK; + } + return ret; + +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index a33e6aa42a4c5..7fd7e7cba0c92 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -3623,11 +3623,11 @@ static void tcp_send_challenge_ack(struct sock *sk, const struct sk_buff *skb) + + /* Then check host-wide RFC 5961 rate limit. */ + now = jiffies / HZ; +- if (now != challenge_timestamp) { ++ if (now != READ_ONCE(challenge_timestamp)) { + u32 ack_limit = READ_ONCE(net->ipv4.sysctl_tcp_challenge_ack_limit); + u32 half = (ack_limit + 1) >> 1; + +- challenge_timestamp = now; ++ WRITE_ONCE(challenge_timestamp, now); + WRITE_ONCE(challenge_count, half + prandom_u32_max(ack_limit)); + } + count = READ_ONCE(challenge_count); +diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c +index 11a715d76a4f1..f780fbe82e7dc 100644 +--- a/net/kcm/kcmsock.c ++++ b/net/kcm/kcmsock.c +@@ -1411,12 +1411,6 @@ static int kcm_attach(struct socket *sock, struct socket *csock, + psock->sk = csk; + psock->bpf_prog = prog; + +- err = strp_init(&psock->strp, csk, &cb); +- if (err) { +- kmem_cache_free(kcm_psockp, psock); +- goto out; +- } +- + write_lock_bh(&csk->sk_callback_lock); + + /* Check if sk_user_data is already by KCM or someone else. +@@ -1424,13 +1418,18 @@ static int kcm_attach(struct socket *sock, struct socket *csock, + */ + if (csk->sk_user_data) { + write_unlock_bh(&csk->sk_callback_lock); +- strp_stop(&psock->strp); +- strp_done(&psock->strp); + kmem_cache_free(kcm_psockp, psock); + err = -EALREADY; + goto out; + } + ++ err = strp_init(&psock->strp, csk, &cb); ++ if (err) { ++ write_unlock_bh(&csk->sk_callback_lock); ++ kmem_cache_free(kcm_psockp, psock); ++ goto out; ++ } ++ + psock->save_data_ready = csk->sk_data_ready; + psock->save_write_space = csk->sk_write_space; + psock->save_state_change = csk->sk_state_change; +diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c +index 5d6ca4c3e6981..1e133ca58e789 100644 +--- a/net/mac80211/ibss.c ++++ b/net/mac80211/ibss.c +@@ -534,6 +534,10 @@ int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata) + + sdata_assert_lock(sdata); + ++ /* When not connected/joined, sending CSA doesn't make sense. */ ++ if (ifibss->state != IEEE80211_IBSS_MLME_JOINED) ++ return -ENOLINK; ++ + /* update cfg80211 bss information with the new channel */ + if (!is_zero_ether_addr(ifibss->bssid)) { + cbss = cfg80211_get_bss(sdata->local->hw.wiphy, +diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c +index 887f945bb12d4..d6afaacaf7ef8 100644 +--- a/net/mac80211/scan.c ++++ b/net/mac80211/scan.c +@@ -461,16 +461,19 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) + scan_req = rcu_dereference_protected(local->scan_req, + lockdep_is_held(&local->mtx)); + +- if (scan_req != local->int_scan_req) { +- local->scan_info.aborted = aborted; +- cfg80211_scan_done(scan_req, &local->scan_info); +- } + RCU_INIT_POINTER(local->scan_req, NULL); + RCU_INIT_POINTER(local->scan_sdata, NULL); + + local->scanning = 0; + local->scan_chandef.chan = NULL; + ++ synchronize_rcu(); ++ ++ if (scan_req != local->int_scan_req) { ++ local->scan_info.aborted = aborted; ++ cfg80211_scan_done(scan_req, &local->scan_info); ++ } ++ + /* Set power back to normal operating levels. */ + ieee80211_hw_config(local, 0); + +diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c +index 6eeef7a61927b..f1e263b2c2957 100644 +--- a/net/mac80211/sta_info.c ++++ b/net/mac80211/sta_info.c +@@ -2206,9 +2206,9 @@ static inline u64 sta_get_tidstats_msdu(struct ieee80211_sta_rx_stats *rxstats, + u64 value; + + do { +- start = u64_stats_fetch_begin(&rxstats->syncp); ++ start = u64_stats_fetch_begin_irq(&rxstats->syncp); + value = rxstats->msdu[tid]; +- } while (u64_stats_fetch_retry(&rxstats->syncp, start)); ++ } while (u64_stats_fetch_retry_irq(&rxstats->syncp, start)); + + return value; + } +@@ -2272,9 +2272,9 @@ static inline u64 sta_get_stats_bytes(struct ieee80211_sta_rx_stats *rxstats) + u64 value; + + do { +- start = u64_stats_fetch_begin(&rxstats->syncp); ++ start = u64_stats_fetch_begin_irq(&rxstats->syncp); + value = rxstats->bytes; +- } while (u64_stats_fetch_retry(&rxstats->syncp, start)); ++ } while (u64_stats_fetch_retry_irq(&rxstats->syncp, start)); + + return value; + } +diff --git a/net/mac802154/rx.c b/net/mac802154/rx.c +index b8ce84618a55b..c439125ef2b91 100644 +--- a/net/mac802154/rx.c ++++ b/net/mac802154/rx.c +@@ -44,7 +44,7 @@ ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata, + + switch (mac_cb(skb)->dest.mode) { + case IEEE802154_ADDR_NONE: +- if (mac_cb(skb)->dest.mode != IEEE802154_ADDR_NONE) ++ if (hdr->source.mode != IEEE802154_ADDR_NONE) + /* FIXME: check if we are PAN coordinator */ + skb->pkt_type = PACKET_OTHERHOST; + else +diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c +index 6e587feb705c4..58a7075084d17 100644 +--- a/net/mpls/af_mpls.c ++++ b/net/mpls/af_mpls.c +@@ -1079,9 +1079,9 @@ static void mpls_get_stats(struct mpls_dev *mdev, + + p = per_cpu_ptr(mdev->stats, i); + do { +- start = u64_stats_fetch_begin(&p->syncp); ++ start = u64_stats_fetch_begin_irq(&p->syncp); + local = p->stats; +- } while (u64_stats_fetch_retry(&p->syncp, start)); ++ } while (u64_stats_fetch_retry_irq(&p->syncp, start)); + + stats->rx_packets += local.rx_packets; + stats->rx_bytes += local.rx_bytes; +diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c +index 67ad08320886b..5e2c83cb7b129 100644 +--- a/net/openvswitch/datapath.c ++++ b/net/openvswitch/datapath.c +@@ -1801,7 +1801,7 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info) + ovs_dp_reset_user_features(skb, info); + } + +- goto err_unlock_and_destroy_meters; ++ goto err_destroy_portids; + } + + err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid, +@@ -1816,6 +1816,8 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info) + ovs_notify(&dp_datapath_genl_family, reply, info); + return 0; + ++err_destroy_portids: ++ kfree(rcu_dereference_raw(dp->upcall_portids)); + err_unlock_and_destroy_meters: + ovs_unlock(); + ovs_meters_exit(dp); +diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c +index 250d87d993cb7..02299785209c1 100644 +--- a/net/sched/sch_generic.c ++++ b/net/sched/sch_generic.c +@@ -1083,6 +1083,21 @@ struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue, + } + EXPORT_SYMBOL(dev_graft_qdisc); + ++static void shutdown_scheduler_queue(struct net_device *dev, ++ struct netdev_queue *dev_queue, ++ void *_qdisc_default) ++{ ++ struct Qdisc *qdisc = dev_queue->qdisc_sleeping; ++ struct Qdisc *qdisc_default = _qdisc_default; ++ ++ if (qdisc) { ++ rcu_assign_pointer(dev_queue->qdisc, qdisc_default); ++ dev_queue->qdisc_sleeping = qdisc_default; ++ ++ qdisc_put(qdisc); ++ } ++} ++ + static void attach_one_default_qdisc(struct net_device *dev, + struct netdev_queue *dev_queue, + void *_unused) +@@ -1130,6 +1145,7 @@ static void attach_default_qdiscs(struct net_device *dev) + if (qdisc == &noop_qdisc) { + netdev_warn(dev, "default qdisc (%s) fail, fallback to %s\n", + default_qdisc_ops->id, noqueue_qdisc_ops.id); ++ netdev_for_each_tx_queue(dev, shutdown_scheduler_queue, &noop_qdisc); + dev->priv_flags |= IFF_NO_QUEUE; + netdev_for_each_tx_queue(dev, attach_one_default_qdisc, NULL); + qdisc = txq->qdisc_sleeping; +@@ -1384,21 +1400,6 @@ void dev_init_scheduler(struct net_device *dev) + timer_setup(&dev->watchdog_timer, dev_watchdog, 0); + } + +-static void shutdown_scheduler_queue(struct net_device *dev, +- struct netdev_queue *dev_queue, +- void *_qdisc_default) +-{ +- struct Qdisc *qdisc = dev_queue->qdisc_sleeping; +- struct Qdisc *qdisc_default = _qdisc_default; +- +- if (qdisc) { +- rcu_assign_pointer(dev_queue->qdisc, qdisc_default); +- dev_queue->qdisc_sleeping = qdisc_default; +- +- qdisc_put(qdisc); +- } +-} +- + void dev_shutdown(struct net_device *dev) + { + netdev_for_each_tx_queue(dev, shutdown_scheduler_queue, &noop_qdisc); +diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c +index 78e79029dc631..6eb17004a9e44 100644 +--- a/net/sched/sch_tbf.c ++++ b/net/sched/sch_tbf.c +@@ -342,6 +342,7 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt, + struct nlattr *tb[TCA_TBF_MAX + 1]; + struct tc_tbf_qopt *qopt; + struct Qdisc *child = NULL; ++ struct Qdisc *old = NULL; + struct psched_ratecfg rate; + struct psched_ratecfg peak; + u64 max_size; +@@ -433,7 +434,7 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt, + sch_tree_lock(sch); + if (child) { + qdisc_tree_flush_backlog(q->qdisc); +- qdisc_put(q->qdisc); ++ old = q->qdisc; + q->qdisc = child; + } + q->limit = qopt->limit; +@@ -453,6 +454,7 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt, + memcpy(&q->peak, &peak, sizeof(struct psched_ratecfg)); + + sch_tree_unlock(sch); ++ qdisc_put(old); + err = 0; + + tbf_offload_change(sch); +diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c +index 2ddd7b34b4ce5..26f81e2e1dfba 100644 +--- a/net/smc/af_smc.c ++++ b/net/smc/af_smc.c +@@ -1490,7 +1490,6 @@ static void smc_listen_out_connected(struct smc_sock *new_smc) + { + struct sock *newsmcsk = &new_smc->sk; + +- sk_refcnt_debug_inc(newsmcsk); + if (newsmcsk->sk_state == SMC_INIT) + newsmcsk->sk_state = SMC_ACTIVE; + +diff --git a/net/wireless/debugfs.c b/net/wireless/debugfs.c +index aab43469a2f04..0878b162890af 100644 +--- a/net/wireless/debugfs.c ++++ b/net/wireless/debugfs.c +@@ -65,9 +65,10 @@ static ssize_t ht40allow_map_read(struct file *file, + { + struct wiphy *wiphy = file->private_data; + char *buf; +- unsigned int offset = 0, buf_size = PAGE_SIZE, i, r; ++ unsigned int offset = 0, buf_size = PAGE_SIZE, i; + enum nl80211_band band; + struct ieee80211_supported_band *sband; ++ ssize_t r; + + buf = kzalloc(buf_size, GFP_KERNEL); + if (!buf) +diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal +index ff805777431ce..ce9661d968a3d 100644 +--- a/scripts/Makefile.modfinal ++++ b/scripts/Makefile.modfinal +@@ -40,7 +40,7 @@ quiet_cmd_ld_ko_o = LD [M] $@ + quiet_cmd_btf_ko = BTF [M] $@ + cmd_btf_ko = \ + if [ -f vmlinux ]; then \ +- LLVM_OBJCOPY="$(OBJCOPY)" $(PAHOLE) -J --btf_base vmlinux $@; \ ++ LLVM_OBJCOPY="$(OBJCOPY)" $(PAHOLE) -J $(PAHOLE_FLAGS) --btf_base vmlinux $@; \ + else \ + printf "Skipping BTF generation for %s due to unavailability of vmlinux\n" $@ 1>&2; \ + fi; +diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh +index 3819a461465d8..57ef6accbb40f 100755 +--- a/scripts/link-vmlinux.sh ++++ b/scripts/link-vmlinux.sh +@@ -211,7 +211,6 @@ vmlinux_link() + gen_btf() + { + local pahole_ver +- local extra_paholeopt= + + if ! [ -x "$(command -v ${PAHOLE})" ]; then + echo >&2 "BTF: ${1}: pahole (${PAHOLE}) is not available" +@@ -226,16 +225,8 @@ gen_btf() + + vmlinux_link ${1} + +- if [ "${pahole_ver}" -ge "118" ] && [ "${pahole_ver}" -le "121" ]; then +- # pahole 1.18 through 1.21 can't handle zero-sized per-CPU vars +- extra_paholeopt="${extra_paholeopt} --skip_encoding_btf_vars" +- fi +- if [ "${pahole_ver}" -ge "121" ]; then +- extra_paholeopt="${extra_paholeopt} --btf_gen_floats" +- fi +- + info "BTF" ${2} +- LLVM_OBJCOPY="${OBJCOPY}" ${PAHOLE} -J ${extra_paholeopt} ${1} ++ LLVM_OBJCOPY="${OBJCOPY}" ${PAHOLE} -J ${PAHOLE_FLAGS} ${1} + + # Create ${2} which contains just .BTF section but no symbols. Add + # SHF_ALLOC because .BTF will be part of the vmlinux image. --strip-all +diff --git a/scripts/pahole-flags.sh b/scripts/pahole-flags.sh +new file mode 100644 +index 0000000000000..7acee326aa6c9 +--- /dev/null ++++ b/scripts/pahole-flags.sh +@@ -0,0 +1,24 @@ ++#!/bin/sh ++# SPDX-License-Identifier: GPL-2.0 ++ ++extra_paholeopt= ++ ++if ! [ -x "$(command -v ${PAHOLE})" ]; then ++ exit 0 ++fi ++ ++pahole_ver=$(${PAHOLE} --version | sed -E 's/v([0-9]+)\.([0-9]+)/\1\2/') ++ ++if [ "${pahole_ver}" -ge "118" ] && [ "${pahole_ver}" -le "121" ]; then ++ # pahole 1.18 through 1.21 can't handle zero-sized per-CPU vars ++ extra_paholeopt="${extra_paholeopt} --skip_encoding_btf_vars" ++fi ++if [ "${pahole_ver}" -ge "121" ]; then ++ extra_paholeopt="${extra_paholeopt} --btf_gen_floats" ++fi ++ ++if [ "${pahole_ver}" -ge "124" ]; then ++ extra_paholeopt="${extra_paholeopt} --skip_encoding_btf_enum64" ++fi ++ ++echo ${extra_paholeopt} +diff --git a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c +index 1e3bf086f8671..07efb38f58ac1 100644 +--- a/sound/core/seq/oss/seq_oss_midi.c ++++ b/sound/core/seq/oss/seq_oss_midi.c +@@ -270,7 +270,9 @@ snd_seq_oss_midi_clear_all(void) + void + snd_seq_oss_midi_setup(struct seq_oss_devinfo *dp) + { ++ spin_lock_irq(®ister_lock); + dp->max_mididev = max_midi_devs; ++ spin_unlock_irq(®ister_lock); + } + + /* +diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c +index 2e9d695d336c9..2d707afa1ef1c 100644 +--- a/sound/core/seq/seq_clientmgr.c ++++ b/sound/core/seq/seq_clientmgr.c +@@ -121,13 +121,13 @@ struct snd_seq_client *snd_seq_client_use_ptr(int clientid) + spin_unlock_irqrestore(&clients_lock, flags); + #ifdef CONFIG_MODULES + if (!in_interrupt()) { +- static char client_requested[SNDRV_SEQ_GLOBAL_CLIENTS]; +- static char card_requested[SNDRV_CARDS]; ++ static DECLARE_BITMAP(client_requested, SNDRV_SEQ_GLOBAL_CLIENTS); ++ static DECLARE_BITMAP(card_requested, SNDRV_CARDS); ++ + if (clientid < SNDRV_SEQ_GLOBAL_CLIENTS) { + int idx; + +- if (!client_requested[clientid]) { +- client_requested[clientid] = 1; ++ if (!test_and_set_bit(clientid, client_requested)) { + for (idx = 0; idx < 15; idx++) { + if (seq_client_load[idx] < 0) + break; +@@ -142,10 +142,8 @@ struct snd_seq_client *snd_seq_client_use_ptr(int clientid) + int card = (clientid - SNDRV_SEQ_GLOBAL_CLIENTS) / + SNDRV_SEQ_CLIENTS_PER_CARD; + if (card < snd_ecards_limit) { +- if (! card_requested[card]) { +- card_requested[card] = 1; ++ if (!test_and_set_bit(card, card_requested)) + snd_request_card(card); +- } + snd_seq_device_load_drivers(); + } + } +diff --git a/sound/hda/intel-nhlt.c b/sound/hda/intel-nhlt.c +index e2237239d922a..8714891f50b0a 100644 +--- a/sound/hda/intel-nhlt.c ++++ b/sound/hda/intel-nhlt.c +@@ -55,20 +55,26 @@ int intel_nhlt_get_dmic_geo(struct device *dev, struct nhlt_acpi_table *nhlt) + + /* find max number of channels based on format_configuration */ + if (fmt_configs->fmt_count) { +- dev_dbg(dev, "%s: found %d format definitions\n", +- __func__, fmt_configs->fmt_count); ++ struct nhlt_fmt_cfg *fmt_cfg = fmt_configs->fmt_config; ++ ++ dev_dbg(dev, "found %d format definitions\n", ++ fmt_configs->fmt_count); + + for (i = 0; i < fmt_configs->fmt_count; i++) { + struct wav_fmt_ext *fmt_ext; + +- fmt_ext = &fmt_configs->fmt_config[i].fmt_ext; ++ fmt_ext = &fmt_cfg->fmt_ext; + + if (fmt_ext->fmt.channels > max_ch) + max_ch = fmt_ext->fmt.channels; ++ ++ /* Move to the next nhlt_fmt_cfg */ ++ fmt_cfg = (struct nhlt_fmt_cfg *)(fmt_cfg->config.caps + ++ fmt_cfg->config.size); + } +- dev_dbg(dev, "%s: max channels found %d\n", __func__, max_ch); ++ dev_dbg(dev, "max channels found %d\n", max_ch); + } else { +- dev_dbg(dev, "%s: No format information found\n", __func__); ++ dev_dbg(dev, "No format information found\n"); + } + + if (cfg->device_config.config_type != NHLT_CONFIG_TYPE_MIC_ARRAY) { +@@ -95,17 +101,16 @@ int intel_nhlt_get_dmic_geo(struct device *dev, struct nhlt_acpi_table *nhlt) + } + + if (dmic_geo > 0) { +- dev_dbg(dev, "%s: Array with %d dmics\n", __func__, dmic_geo); ++ dev_dbg(dev, "Array with %d dmics\n", dmic_geo); + } + if (max_ch > dmic_geo) { +- dev_dbg(dev, "%s: max channels %d exceed dmic number %d\n", +- __func__, max_ch, dmic_geo); ++ dev_dbg(dev, "max channels %d exceed dmic number %d\n", ++ max_ch, dmic_geo); + } + } + } + +- dev_dbg(dev, "%s: dmic number %d max_ch %d\n", +- __func__, dmic_geo, max_ch); ++ dev_dbg(dev, "dmic number %d max_ch %d\n", dmic_geo, max_ch); + + return dmic_geo; + } +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index 600ba91f77031..45b8ebda284d9 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -4684,6 +4684,48 @@ static void alc236_fixup_hp_mute_led_micmute_vref(struct hda_codec *codec, + alc236_fixup_hp_micmute_led_vref(codec, fix, action); + } + ++static inline void alc298_samsung_write_coef_pack(struct hda_codec *codec, ++ const unsigned short coefs[2]) ++{ ++ alc_write_coef_idx(codec, 0x23, coefs[0]); ++ alc_write_coef_idx(codec, 0x25, coefs[1]); ++ alc_write_coef_idx(codec, 0x26, 0xb011); ++} ++ ++struct alc298_samsung_amp_desc { ++ unsigned char nid; ++ unsigned short init_seq[2][2]; ++}; ++ ++static void alc298_fixup_samsung_amp(struct hda_codec *codec, ++ const struct hda_fixup *fix, int action) ++{ ++ int i, j; ++ static const unsigned short init_seq[][2] = { ++ { 0x19, 0x00 }, { 0x20, 0xc0 }, { 0x22, 0x44 }, { 0x23, 0x08 }, ++ { 0x24, 0x85 }, { 0x25, 0x41 }, { 0x35, 0x40 }, { 0x36, 0x01 }, ++ { 0x38, 0x81 }, { 0x3a, 0x03 }, { 0x3b, 0x81 }, { 0x40, 0x3e }, ++ { 0x41, 0x07 }, { 0x400, 0x1 } ++ }; ++ static const struct alc298_samsung_amp_desc amps[] = { ++ { 0x3a, { { 0x18, 0x1 }, { 0x26, 0x0 } } }, ++ { 0x39, { { 0x18, 0x2 }, { 0x26, 0x1 } } } ++ }; ++ ++ if (action != HDA_FIXUP_ACT_INIT) ++ return; ++ ++ for (i = 0; i < ARRAY_SIZE(amps); i++) { ++ alc_write_coef_idx(codec, 0x22, amps[i].nid); ++ ++ for (j = 0; j < ARRAY_SIZE(amps[i].init_seq); j++) ++ alc298_samsung_write_coef_pack(codec, amps[i].init_seq[j]); ++ ++ for (j = 0; j < ARRAY_SIZE(init_seq); j++) ++ alc298_samsung_write_coef_pack(codec, init_seq[j]); ++ } ++} ++ + #if IS_REACHABLE(CONFIG_INPUT) + static void gpio2_mic_hotkey_event(struct hda_codec *codec, + struct hda_jack_callback *event) +@@ -6842,6 +6884,7 @@ enum { + ALC236_FIXUP_HP_GPIO_LED, + ALC236_FIXUP_HP_MUTE_LED, + ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF, ++ ALC298_FIXUP_SAMSUNG_AMP, + ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, + ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, + ALC295_FIXUP_ASUS_MIC_NO_PRESENCE, +@@ -8196,6 +8239,12 @@ static const struct hda_fixup alc269_fixups[] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc236_fixup_hp_mute_led_micmute_vref, + }, ++ [ALC298_FIXUP_SAMSUNG_AMP] = { ++ .type = HDA_FIXUP_FUNC, ++ .v.func = alc298_fixup_samsung_amp, ++ .chained = true, ++ .chain_id = ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET ++ }, + [ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { +@@ -8985,13 +9034,13 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x10ec, 0x1254, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK), + SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-SZ6", ALC269_FIXUP_HEADSET_MODE), + SND_PCI_QUIRK(0x144d, 0xc109, "Samsung Ativ book 9 (NP900X3G)", ALC269_FIXUP_INV_DMIC), +- SND_PCI_QUIRK(0x144d, 0xc169, "Samsung Notebook 9 Pen (NP930SBE-K01US)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), +- SND_PCI_QUIRK(0x144d, 0xc176, "Samsung Notebook 9 Pro (NP930MBE-K04US)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), +- SND_PCI_QUIRK(0x144d, 0xc189, "Samsung Galaxy Flex Book (NT950QCG-X716)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), +- SND_PCI_QUIRK(0x144d, 0xc18a, "Samsung Galaxy Book Ion (NP930XCJ-K01US)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), ++ SND_PCI_QUIRK(0x144d, 0xc169, "Samsung Notebook 9 Pen (NP930SBE-K01US)", ALC298_FIXUP_SAMSUNG_AMP), ++ SND_PCI_QUIRK(0x144d, 0xc176, "Samsung Notebook 9 Pro (NP930MBE-K04US)", ALC298_FIXUP_SAMSUNG_AMP), ++ SND_PCI_QUIRK(0x144d, 0xc189, "Samsung Galaxy Flex Book (NT950QCG-X716)", ALC298_FIXUP_SAMSUNG_AMP), ++ SND_PCI_QUIRK(0x144d, 0xc18a, "Samsung Galaxy Book Ion (NP930XCJ-K01US)", ALC298_FIXUP_SAMSUNG_AMP), + SND_PCI_QUIRK(0x144d, 0xc740, "Samsung Ativ book 8 (NP870Z5G)", ALC269_FIXUP_ATIV_BOOK_8), +- SND_PCI_QUIRK(0x144d, 0xc812, "Samsung Notebook Pen S (NT950SBE-X58)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), +- SND_PCI_QUIRK(0x144d, 0xc830, "Samsung Galaxy Book Ion (NT950XCJ-X716A)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), ++ SND_PCI_QUIRK(0x144d, 0xc812, "Samsung Notebook Pen S (NT950SBE-X58)", ALC298_FIXUP_SAMSUNG_AMP), ++ SND_PCI_QUIRK(0x144d, 0xc830, "Samsung Galaxy Book Ion (NT950XCJ-X716A)", ALC298_FIXUP_SAMSUNG_AMP), + SND_PCI_QUIRK(0x144d, 0xc832, "Samsung Galaxy Book Flex Alpha (NP730QCJ)", ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), + SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_HEADSET_MIC), + SND_PCI_QUIRK(0x1462, 0xb120, "MSI Cubi MS-B120", ALC283_FIXUP_HEADSET_MIC), +@@ -9351,7 +9400,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = { + {.id = ALC299_FIXUP_PREDATOR_SPK, .name = "predator-spk"}, + {.id = ALC298_FIXUP_HUAWEI_MBX_STEREO, .name = "huawei-mbx-stereo"}, + {.id = ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE, .name = "alc256-medion-headset"}, +- {.id = ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, .name = "alc298-samsung-headphone"}, ++ {.id = ALC298_FIXUP_SAMSUNG_AMP, .name = "alc298-samsung-amp"}, + {.id = ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, .name = "alc256-samsung-headphone"}, + {.id = ALC255_FIXUP_XIAOMI_HEADSET_MIC, .name = "alc255-xiaomi-headset"}, + {.id = ALC274_FIXUP_HP_MIC, .name = "alc274-hp-mic-detect"}, |