diff options
Diffstat (limited to 'drivers')
83 files changed, 2180 insertions, 596 deletions
diff --git a/drivers/firmware/efi/libstub/loongarch.c b/drivers/firmware/efi/libstub/loongarch.c index 3782d0a187d1..9825f5218137 100644 --- a/drivers/firmware/efi/libstub/loongarch.c +++ b/drivers/firmware/efi/libstub/loongarch.c @@ -72,10 +72,10 @@ efi_status_t efi_boot_kernel(void *handle, efi_loaded_image_t *image, desc_ver, priv.runtime_map); /* Config Direct Mapping */ - csr_write64(CSR_DMW0_INIT, LOONGARCH_CSR_DMWIN0); - csr_write64(CSR_DMW1_INIT, LOONGARCH_CSR_DMWIN1); - csr_write64(CSR_DMW2_INIT, LOONGARCH_CSR_DMWIN2); - csr_write64(CSR_DMW3_INIT, LOONGARCH_CSR_DMWIN3); + csr_write(CSR_DMW0_INIT, LOONGARCH_CSR_DMWIN0); + csr_write(CSR_DMW1_INIT, LOONGARCH_CSR_DMWIN1); + csr_write(CSR_DMW2_INIT, LOONGARCH_CSR_DMWIN2); + csr_write(CSR_DMW3_INIT, LOONGARCH_CSR_DMWIN3); real_kernel_entry = (void *)kernel_entry_address(kernel_addr, image); diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index c74da29253e8..bd185482a7fd 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -737,7 +737,6 @@ config GPIO_TB10X depends on ARC_PLAT_TB10X || COMPILE_TEST select GPIO_GENERIC select GENERIC_IRQ_CHIP - select OF_GPIO config GPIO_TEGRA tristate "NVIDIA Tegra GPIO support" @@ -1568,6 +1567,7 @@ config GPIO_QIXIS_FPGA tristate "NXP QIXIS FPGA GPIO support" depends on MFD_SIMPLE_MFD_I2C || COMPILE_TEST select GPIO_REGMAP + select REGMAP_MMIO help This enables support for the GPIOs found in the QIXIS FPGA which is integrated on some NXP Layerscape boards such as LX2160ARDB and diff --git a/drivers/gpio/gpio-mmio.c b/drivers/gpio/gpio-mmio.c index b3a26a06260b..5daf962b0323 100644 --- a/drivers/gpio/gpio-mmio.c +++ b/drivers/gpio/gpio-mmio.c @@ -231,7 +231,7 @@ static int gpio_mmio_set(struct gpio_chip *gc, unsigned int gpio, int val) struct gpio_generic_chip *chip = to_gpio_generic_chip(gc); unsigned long mask = gpio_mmio_line2mask(gc, gpio); - guard(raw_spinlock)(&chip->lock); + guard(raw_spinlock_irqsave)(&chip->lock); if (val) chip->sdata |= mask; @@ -262,7 +262,7 @@ static int gpio_mmio_set_set(struct gpio_chip *gc, unsigned int gpio, int val) struct gpio_generic_chip *chip = to_gpio_generic_chip(gc); unsigned long mask = gpio_mmio_line2mask(gc, gpio); - guard(raw_spinlock)(&chip->lock); + guard(raw_spinlock_irqsave)(&chip->lock); if (val) chip->sdata |= mask; @@ -302,7 +302,7 @@ static void gpio_mmio_set_multiple_single_reg(struct gpio_chip *gc, struct gpio_generic_chip *chip = to_gpio_generic_chip(gc); unsigned long set_mask, clear_mask; - guard(raw_spinlock)(&chip->lock); + guard(raw_spinlock_irqsave)(&chip->lock); gpio_mmio_multiple_get_masks(gc, mask, bits, &set_mask, &clear_mask); @@ -391,7 +391,7 @@ static int gpio_mmio_dir_in(struct gpio_chip *gc, unsigned int gpio) { struct gpio_generic_chip *chip = to_gpio_generic_chip(gc); - scoped_guard(raw_spinlock, &chip->lock) { + scoped_guard(raw_spinlock_irqsave, &chip->lock) { chip->sdir &= ~gpio_mmio_line2mask(gc, gpio); if (chip->reg_dir_in) @@ -431,7 +431,7 @@ static void gpio_mmio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) { struct gpio_generic_chip *chip = to_gpio_generic_chip(gc); - guard(raw_spinlock)(&chip->lock); + guard(raw_spinlock_irqsave)(&chip->lock); chip->sdir |= gpio_mmio_line2mask(gc, gpio); diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c index e5ba38e65c10..9581bd5ca947 100644 --- a/drivers/gpio/gpio-regmap.c +++ b/drivers/gpio/gpio-regmap.c @@ -338,7 +338,7 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config config->regmap_irq_line, config->regmap_irq_flags, 0, config->regmap_irq_chip, &gpio->irq_chip_data); if (ret) - goto err_free_bitmap; + goto err_remove_gpiochip; irq_domain = regmap_irq_get_domain(gpio->irq_chip_data); } else diff --git a/drivers/gpio/gpiolib-acpi-quirks.c b/drivers/gpio/gpiolib-acpi-quirks.c index 7b95d1b03361..a0116f004975 100644 --- a/drivers/gpio/gpiolib-acpi-quirks.c +++ b/drivers/gpio/gpiolib-acpi-quirks.c @@ -370,6 +370,28 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] __initconst = { .ignore_wake = "ASCP1A00:00@8", }, }, + { + /* + * Spurious wakeups, likely from touchpad controller + * Dell Precision 7780 + * Found in BIOS 1.24.1 + * + * Found in touchpad firmware, installed by Dell Touchpad Firmware Update Utility version 1160.4196.9, A01 + * ( Dell-Touchpad-Firmware-Update-Utility_VYGNN_WIN64_1160.4196.9_A00.EXE ), + * released on 11 Jul 2024 + * + * https://lore.kernel.org/linux-i2c/197ae95ffd8.dc819e60457077.7692120488609091556@zohomail.com/ + */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_FAMILY, "Precision"), + DMI_MATCH(DMI_PRODUCT_NAME, "Precision 7780"), + DMI_MATCH(DMI_BOARD_NAME, "0C6JVW"), + }, + .driver_data = &(struct acpi_gpiolib_dmi_quirk) { + .ignore_wake = "VEN_0488:00@355", + }, + }, {} /* Terminating entry */ }; diff --git a/drivers/gpio/gpiolib-shared.c b/drivers/gpio/gpiolib-shared.c index 8bdd107b1ad1..ba4b718d40a0 100644 --- a/drivers/gpio/gpiolib-shared.c +++ b/drivers/gpio/gpiolib-shared.c @@ -36,6 +36,8 @@ struct gpio_shared_ref { enum gpiod_flags flags; char *con_id; int dev_id; + /* Protects the auxiliary device struct and the lookup table. */ + struct mutex lock; struct auxiliary_device adev; struct gpiod_lookup_table *lookup; }; @@ -49,6 +51,7 @@ struct gpio_shared_entry { unsigned int offset; /* Index in the property value array. */ size_t index; + /* Synchronizes the modification of shared_desc. */ struct mutex lock; struct gpio_shared_desc *shared_desc; struct kref ref; @@ -56,7 +59,6 @@ struct gpio_shared_entry { }; static LIST_HEAD(gpio_shared_list); -static DEFINE_MUTEX(gpio_shared_lock); static DEFINE_IDA(gpio_shared_ida); #if IS_ENABLED(CONFIG_OF) @@ -77,6 +79,10 @@ gpio_shared_find_entry(struct fwnode_handle *controller_node, /* Handle all special nodes that we should ignore. */ static bool gpio_shared_of_node_ignore(struct device_node *node) { + /* Ignore disabled devices. */ + if (!of_device_is_available(node)) + return true; + /* * __symbols__ is a special, internal node and should not be considered * when scanning for shared GPIOs. @@ -183,6 +189,7 @@ static int gpio_shared_of_traverse(struct device_node *curr) ref->fwnode = fwnode_handle_get(of_fwnode_handle(curr)); ref->flags = args.args[1]; + mutex_init(&ref->lock); if (strends(prop->name, "gpios")) suffix = "-gpios"; @@ -254,7 +261,7 @@ static int gpio_shared_make_adev(struct gpio_device *gdev, struct auxiliary_device *adev = &ref->adev; int ret; - lockdep_assert_held(&gpio_shared_lock); + guard(mutex)(&ref->lock); memset(adev, 0, sizeof(*adev)); @@ -369,14 +376,14 @@ int gpio_shared_add_proxy_lookup(struct device *consumer, unsigned long lflags) if (!lookup) return -ENOMEM; - guard(mutex)(&gpio_shared_lock); - list_for_each_entry(entry, &gpio_shared_list, list) { list_for_each_entry(ref, &entry->refs, list) { if (!device_match_fwnode(consumer, ref->fwnode) && !gpio_shared_dev_is_reset_gpio(consumer, entry, ref)) continue; + guard(mutex)(&ref->lock); + /* We've already done that on a previous request. */ if (ref->lookup) return 0; @@ -395,7 +402,8 @@ int gpio_shared_add_proxy_lookup(struct device *consumer, unsigned long lflags) lookup->table[0] = GPIO_LOOKUP(no_free_ptr(key), 0, ref->con_id, lflags); - gpiod_add_lookup_table(no_free_ptr(lookup)); + ref->lookup = no_free_ptr(lookup); + gpiod_add_lookup_table(ref->lookup); return 0; } @@ -408,10 +416,8 @@ int gpio_shared_add_proxy_lookup(struct device *consumer, unsigned long lflags) static void gpio_shared_remove_adev(struct auxiliary_device *adev) { - lockdep_assert_held(&gpio_shared_lock); - - auxiliary_device_uninit(adev); auxiliary_device_delete(adev); + auxiliary_device_uninit(adev); } int gpio_device_setup_shared(struct gpio_device *gdev) @@ -421,8 +427,6 @@ int gpio_device_setup_shared(struct gpio_device *gdev) unsigned long *flags; int ret; - guard(mutex)(&gpio_shared_lock); - list_for_each_entry(entry, &gpio_shared_list, list) { list_for_each_entry(ref, &entry->refs, list) { if (gdev->dev.parent == &ref->adev.dev) { @@ -479,19 +483,32 @@ void gpio_device_teardown_shared(struct gpio_device *gdev) struct gpio_shared_entry *entry; struct gpio_shared_ref *ref; - guard(mutex)(&gpio_shared_lock); - list_for_each_entry(entry, &gpio_shared_list, list) { if (!device_match_fwnode(&gdev->dev, entry->fwnode)) continue; + /* + * For some reason if we call synchronize_srcu() in GPIO core, + * descent here and take this mutex and then recursively call + * synchronize_srcu() again from gpiochip_remove() (which is + * totally fine) called after gpio_shared_remove_adev(), + * lockdep prints a false positive deadlock splat. Disable + * lockdep here. + */ + lockdep_off(); list_for_each_entry(ref, &entry->refs, list) { - gpiod_remove_lookup_table(ref->lookup); - kfree(ref->lookup->table[0].key); - kfree(ref->lookup); - ref->lookup = NULL; + guard(mutex)(&ref->lock); + + if (ref->lookup) { + gpiod_remove_lookup_table(ref->lookup); + kfree(ref->lookup->table[0].key); + kfree(ref->lookup); + ref->lookup = NULL; + } + gpio_shared_remove_adev(&ref->adev); } + lockdep_on(); } } @@ -515,8 +532,6 @@ static void gpiod_shared_put(void *data) { struct gpio_shared_entry *entry = data; - lockdep_assert_not_held(&gpio_shared_lock); - kref_put(&entry->ref, gpio_shared_release); } @@ -554,8 +569,6 @@ struct gpio_shared_desc *devm_gpiod_shared_get(struct device *dev) struct gpio_shared_entry *entry; int ret; - lockdep_assert_not_held(&gpio_shared_lock); - entry = dev_get_platdata(dev); if (WARN_ON(!entry)) /* Programmer bug */ @@ -590,6 +603,7 @@ EXPORT_SYMBOL_GPL(devm_gpiod_shared_get); static void gpio_shared_drop_ref(struct gpio_shared_ref *ref) { list_del(&ref->list); + mutex_destroy(&ref->lock); kfree(ref->con_id); ida_free(&gpio_shared_ida, ref->dev_id); fwnode_handle_put(ref->fwnode); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index a67285118c37..c362d4dfb5bb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -1069,7 +1069,9 @@ amdgpu_vm_tlb_flush(struct amdgpu_vm_update_params *params, } /* Prepare a TLB flush fence to be attached to PTs */ - if (!params->unlocked) { + if (!params->unlocked && + /* SI doesn't support pasid or KIQ/MES */ + params->adev->family > AMDGPU_FAMILY_SI) { amdgpu_vm_tlb_fence_create(params->adev, vm, fence); /* Makes sure no PD/PT is freed before the flush */ diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c index b107ee80e472..1f6a22983c0d 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c @@ -265,6 +265,8 @@ static int vcn_v4_0_5_sw_fini(struct amdgpu_ip_block *ip_block) if (amdgpu_sriov_vf(adev)) amdgpu_virt_free_mm_table(adev); + amdgpu_vcn_sysfs_reset_mask_fini(adev); + for (i = 0; i < adev->vcn.num_vcn_inst; i++) { r = amdgpu_vcn_suspend(adev, i); if (r) diff --git a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h index 0320163b6e74..f98c735b2905 100644 --- a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h +++ b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h @@ -3644,14 +3644,18 @@ static const uint32_t cwsr_trap_gfx9_4_3_hex[] = { }; static const uint32_t cwsr_trap_gfx12_hex[] = { - 0xbfa00001, 0xbfa002a2, - 0xb0804009, 0xb8f8f804, + 0xbfa00001, 0xbfa002b2, + 0xb0804009, 0xb8eef81a, + 0xbf880000, 0xb980081a, + 0x00000000, 0xb8f8f804, + 0x9177ff77, 0x0c000000, + 0x846e9a6e, 0x8c776e77, 0x9178ff78, 0x00008c00, 0xb8fbf811, 0x8b6eff78, 0x00004000, 0xbfa10008, 0x8b6eff7b, 0x00000080, 0xbfa20018, 0x8b6ea07b, - 0xbfa20042, 0xbf830010, + 0xbfa2004a, 0xbf830010, 0xb8fbf811, 0xbfa0fffb, 0x8b6eff7b, 0x00000bd0, 0xbfa20010, 0xb8eef812, @@ -3662,28 +3666,32 @@ static const uint32_t cwsr_trap_gfx12_hex[] = { 0xf0000000, 0xbfa20005, 0x8b6fff6f, 0x00000200, 0xbfa20002, 0x8b6ea07b, - 0xbfa2002c, 0xbefa4d82, + 0xbfa20034, 0xbefa4d82, 0xbf8a0000, 0x84fa887a, 0xbf0d8f7b, 0xbfa10002, 0x8c7bff7b, 0xffff0000, - 0xf4601bbd, 0xf8000010, - 0xbf8a0000, 0x846e976e, - 0x9177ff77, 0x00800000, - 0x8c776e77, 0xf4603bbd, - 0xf8000000, 0xbf8a0000, - 0xf4603ebd, 0xf8000008, - 0xbf8a0000, 0x8bee6e6e, - 0xbfa10001, 0xbe80486e, - 0x8b6eff6d, 0xf0000000, - 0xbfa20009, 0xb8eef811, - 0x8b6eff6e, 0x00000080, - 0xbfa20007, 0x8c78ff78, - 0x00004000, 0x80ec886c, - 0x82ed806d, 0xbfa00002, - 0x806c846c, 0x826d806d, - 0x8b6dff6d, 0x0000ffff, - 0x8bfe7e7e, 0x8bea6a6a, - 0x85788978, 0xb9783244, + 0x8b6eff77, 0x0c000000, + 0x916dff6d, 0x0c000000, + 0x8c6d6e6d, 0xf4601bbd, + 0xf8000010, 0xbf8a0000, + 0x846e976e, 0x9177ff77, + 0x00800000, 0x8c776e77, + 0xf4603bbd, 0xf8000000, + 0xbf8a0000, 0xf4603ebd, + 0xf8000008, 0xbf8a0000, + 0x8bee6e6e, 0xbfa10001, + 0xbe80486e, 0x8b6eff6d, + 0xf0000000, 0xbfa20009, + 0xb8eef811, 0x8b6eff6e, + 0x00000080, 0xbfa20007, + 0x8c78ff78, 0x00004000, + 0x80ec886c, 0x82ed806d, + 0xbfa00002, 0x806c846c, + 0x826d806d, 0x8b6dff6d, + 0x0000ffff, 0x8bfe7e7e, + 0x8bea6a6a, 0x85788978, + 0x936eff77, 0x0002001a, + 0xb96ef81a, 0xb9783244, 0xbe804a6c, 0xb8faf802, 0xbf0d987a, 0xbfa10001, 0xbfb00000, 0x8b6dff6d, @@ -3981,7 +3989,7 @@ static const uint32_t cwsr_trap_gfx12_hex[] = { 0x008ce800, 0x00000000, 0x807d817d, 0x8070ff70, 0x00000080, 0xbf0a7b7d, - 0xbfa2fff7, 0xbfa0016e, + 0xbfa2fff7, 0xbfa00171, 0xbef4007e, 0x8b75ff7f, 0x0000ffff, 0x8c75ff75, 0x00040000, 0xbef60080, @@ -4163,12 +4171,14 @@ static const uint32_t cwsr_trap_gfx12_hex[] = { 0xf8000074, 0xbf8a0000, 0x8b6dff6d, 0x0000ffff, 0x8bfe7e7e, 0x8bea6a6a, - 0xb97af804, 0xbe804ec2, - 0xbf94fffe, 0xbe804a6c, + 0x936eff77, 0x0002001a, + 0xb96ef81a, 0xb97af804, 0xbe804ec2, 0xbf94fffe, - 0xbfb10000, 0xbf9f0000, + 0xbe804a6c, 0xbe804ec2, + 0xbf94fffe, 0xbfb10000, 0xbf9f0000, 0xbf9f0000, 0xbf9f0000, 0xbf9f0000, + 0xbf9f0000, 0x00000000, }; static const uint32_t cwsr_trap_gfx9_5_0_hex[] = { diff --git a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx12.asm b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx12.asm index 5a1a1b1f897f..07999b4649de 100644 --- a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx12.asm +++ b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx12.asm @@ -78,9 +78,16 @@ var SQ_WAVE_EXCP_FLAG_PRIV_RESTORE_PART_2_SHIFT = SQ_WAVE_EXCP_FLAG_PRIV_ILLEGAL var SQ_WAVE_EXCP_FLAG_PRIV_RESTORE_PART_2_SIZE = SQ_WAVE_EXCP_FLAG_PRIV_HOST_TRAP_SHIFT - SQ_WAVE_EXCP_FLAG_PRIV_ILLEGAL_INST_SHIFT var SQ_WAVE_EXCP_FLAG_PRIV_RESTORE_PART_3_SHIFT = SQ_WAVE_EXCP_FLAG_PRIV_WAVE_START_SHIFT var SQ_WAVE_EXCP_FLAG_PRIV_RESTORE_PART_3_SIZE = 32 - SQ_WAVE_EXCP_FLAG_PRIV_RESTORE_PART_3_SHIFT + +var SQ_WAVE_SCHED_MODE_DEP_MODE_SHIFT = 0 +var SQ_WAVE_SCHED_MODE_DEP_MODE_SIZE = 2 + var BARRIER_STATE_SIGNAL_OFFSET = 16 var BARRIER_STATE_VALID_OFFSET = 0 +var TTMP11_SCHED_MODE_SHIFT = 26 +var TTMP11_SCHED_MODE_SIZE = 2 +var TTMP11_SCHED_MODE_MASK = 0xC000000 var TTMP11_DEBUG_TRAP_ENABLED_SHIFT = 23 var TTMP11_DEBUG_TRAP_ENABLED_MASK = 0x800000 @@ -160,8 +167,19 @@ L_JUMP_TO_RESTORE: s_branch L_RESTORE L_SKIP_RESTORE: + // Assume most relaxed scheduling mode is set. Save and revert to normal mode. + s_getreg_b32 ttmp2, hwreg(HW_REG_WAVE_SCHED_MODE) + s_wait_alu 0 + s_setreg_imm32_b32 hwreg(HW_REG_WAVE_SCHED_MODE, \ + SQ_WAVE_SCHED_MODE_DEP_MODE_SHIFT, SQ_WAVE_SCHED_MODE_DEP_MODE_SIZE), 0 + s_getreg_b32 s_save_state_priv, hwreg(HW_REG_WAVE_STATE_PRIV) //save STATUS since we will change SCC + // Save SCHED_MODE[1:0] into ttmp11[27:26]. + s_andn2_b32 ttmp11, ttmp11, TTMP11_SCHED_MODE_MASK + s_lshl_b32 ttmp2, ttmp2, TTMP11_SCHED_MODE_SHIFT + s_or_b32 ttmp11, ttmp11, ttmp2 + // Clear SPI_PRIO: do not save with elevated priority. // Clear ECC_ERR: prevents SQC store and triggers FATAL_HALT if setreg'd. s_andn2_b32 s_save_state_priv, s_save_state_priv, SQ_WAVE_STATE_PRIV_ALWAYS_CLEAR_MASK @@ -238,6 +256,13 @@ L_FETCH_2ND_TRAP: s_cbranch_scc0 L_NO_SIGN_EXTEND_TMA s_or_b32 ttmp15, ttmp15, 0xFFFF0000 L_NO_SIGN_EXTEND_TMA: +#if ASIC_FAMILY == CHIP_GFX12 + // Move SCHED_MODE[1:0] from ttmp11 to unused bits in ttmp1[27:26] (return PC_HI). + // The second-level trap will restore from ttmp1 for backwards compatibility. + s_and_b32 ttmp2, ttmp11, TTMP11_SCHED_MODE_MASK + s_andn2_b32 ttmp1, ttmp1, TTMP11_SCHED_MODE_MASK + s_or_b32 ttmp1, ttmp1, ttmp2 +#endif s_load_dword ttmp2, [ttmp14, ttmp15], 0x10 scope:SCOPE_SYS // debug trap enabled flag s_wait_idle @@ -287,6 +312,10 @@ L_EXIT_TRAP: // STATE_PRIV.BARRIER_COMPLETE may have changed since we read it. // Only restore fields which the trap handler changes. s_lshr_b32 s_save_state_priv, s_save_state_priv, SQ_WAVE_STATE_PRIV_SCC_SHIFT + + // Assume relaxed scheduling mode after this point. + restore_sched_mode(ttmp2) + s_setreg_b32 hwreg(HW_REG_WAVE_STATE_PRIV, SQ_WAVE_STATE_PRIV_SCC_SHIFT, \ SQ_WAVE_STATE_PRIV_POISON_ERR_SHIFT - SQ_WAVE_STATE_PRIV_SCC_SHIFT + 1), s_save_state_priv @@ -1043,6 +1072,9 @@ L_SKIP_BARRIER_RESTORE: s_and_b64 exec, exec, exec // Restore STATUS.EXECZ, not writable by s_setreg_b32 s_and_b64 vcc, vcc, vcc // Restore STATUS.VCCZ, not writable by s_setreg_b32 + // Assume relaxed scheduling mode after this point. + restore_sched_mode(s_restore_tmp) + s_setreg_b32 hwreg(HW_REG_WAVE_STATE_PRIV), s_restore_state_priv // SCC is included, which is changed by previous salu // Make barrier and LDS state visible to all waves in the group. @@ -1134,3 +1166,8 @@ function valu_sgpr_hazard end #endif end + +function restore_sched_mode(s_tmp) + s_bfe_u32 s_tmp, ttmp11, (TTMP11_SCHED_MODE_SHIFT | (TTMP11_SCHED_MODE_SIZE << 0x10)) + s_setreg_b32 hwreg(HW_REG_WAVE_SCHED_MODE), s_tmp +end diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_queue.c b/drivers/gpu/drm/amd/amdkfd/kfd_queue.c index f1e7583650c4..80c4fa2b0975 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_queue.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_queue.c @@ -409,6 +409,7 @@ static u32 kfd_get_vgpr_size_per_cu(u32 gfxv) vgpr_size = 0x80000; else if (gfxv == 110000 || /* GFX_VERSION_PLUM_BONITO */ gfxv == 110001 || /* GFX_VERSION_WHEAT_NAS */ + gfxv == 110501 || /* GFX_VERSION_GFX1151 */ gfxv == 120000 || /* GFX_VERSION_GFX1200 */ gfxv == 120001) /* GFX_VERSION_GFX1201 */ vgpr_size = 0x60000; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index 97c2270f278f..79ea138897fc 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -1144,30 +1144,48 @@ static int svm_range_split_tail(struct svm_range *prange, uint64_t new_last, struct list_head *insert_list, struct list_head *remap_list) { + unsigned long last_align_down = ALIGN_DOWN(prange->last, 512); + unsigned long start_align = ALIGN(prange->start, 512); + bool huge_page_mapping = last_align_down > start_align; struct svm_range *tail = NULL; - int r = svm_range_split(prange, prange->start, new_last, &tail); + int r; - if (!r) { - list_add(&tail->list, insert_list); - if (!IS_ALIGNED(new_last + 1, 1UL << prange->granularity)) - list_add(&tail->update_list, remap_list); - } - return r; + r = svm_range_split(prange, prange->start, new_last, &tail); + + if (r) + return r; + + list_add(&tail->list, insert_list); + + if (huge_page_mapping && tail->start > start_align && + tail->start < last_align_down && (!IS_ALIGNED(tail->start, 512))) + list_add(&tail->update_list, remap_list); + + return 0; } static int svm_range_split_head(struct svm_range *prange, uint64_t new_start, struct list_head *insert_list, struct list_head *remap_list) { + unsigned long last_align_down = ALIGN_DOWN(prange->last, 512); + unsigned long start_align = ALIGN(prange->start, 512); + bool huge_page_mapping = last_align_down > start_align; struct svm_range *head = NULL; - int r = svm_range_split(prange, new_start, prange->last, &head); + int r; - if (!r) { - list_add(&head->list, insert_list); - if (!IS_ALIGNED(new_start, 1UL << prange->granularity)) - list_add(&head->update_list, remap_list); - } - return r; + r = svm_range_split(prange, new_start, prange->last, &head); + + if (r) + return r; + + list_add(&head->list, insert_list); + + if (huge_page_mapping && head->last + 1 > start_align && + head->last + 1 < last_align_down && (!IS_ALIGNED(head->last, 512))) + list_add(&head->update_list, remap_list); + + return 0; } static void diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c index 811636af14ea..3eb32d58a120 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c @@ -491,6 +491,10 @@ static ssize_t node_show(struct kobject *kobj, struct attribute *attr, dev->node_props.num_sdma_queues_per_engine); sysfs_show_32bit_prop(buffer, offs, "num_cp_queues", dev->node_props.num_cp_queues); + sysfs_show_32bit_prop(buffer, offs, "cwsr_size", + dev->node_props.cwsr_size); + sysfs_show_32bit_prop(buffer, offs, "ctl_stack_size", + dev->node_props.ctl_stack_size); if (dev->gpu) { log_max_watch_addr = diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h index ef97cede9926..bd0403005f37 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -1063,6 +1063,9 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, void amdgpu_dm_update_connector_after_detect( struct amdgpu_dm_connector *aconnector); +void populate_hdmi_info_from_connector(struct drm_hdmi_info *info, + struct dc_edid_caps *edid_caps); + extern const struct drm_encoder_helper_funcs amdgpu_dm_encoder_helper_funcs; int amdgpu_dm_process_dmub_aux_transfer_sync(struct dc_context *ctx, unsigned int link_index, diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c index ac98c746c3de..e5e993d3ef74 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c @@ -139,6 +139,9 @@ enum dc_edid_status dm_helpers_parse_edid_caps( edid_caps->edid_hdmi = connector->display_info.is_hdmi; + if (edid_caps->edid_hdmi) + populate_hdmi_info_from_connector(&connector->display_info.hdmi, edid_caps); + apply_edid_quirks(dev, edid_buf, edid_caps); sad_count = drm_edid_to_sad((struct edid *) edid->raw_edid, &sads); @@ -990,6 +993,11 @@ dm_helpers_read_acpi_edid(struct amdgpu_dm_connector *aconnector) return drm_edid_read_custom(connector, dm_helpers_probe_acpi_edid, connector); } +void populate_hdmi_info_from_connector(struct drm_hdmi_info *hdmi, struct dc_edid_caps *edid_caps) +{ + edid_caps->scdc_present = hdmi->scdc.supported; +} + enum dc_edid_status dm_helpers_read_local_edid( struct dc_context *ctx, struct dc_link *link, diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index dbd1da4d85d3..5e92eaa67aa3 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -884,28 +884,26 @@ struct dsc_mst_fairness_params { }; #if defined(CONFIG_DRM_AMD_DC_FP) -static uint64_t kbps_to_pbn(int kbps, bool is_peak_pbn) +static uint16_t get_fec_overhead_multiplier(struct dc_link *dc_link) { - uint64_t effective_kbps = (uint64_t)kbps; + u8 link_coding_cap; + uint16_t fec_overhead_multiplier_x1000 = PBN_FEC_OVERHEAD_MULTIPLIER_8B_10B; - if (is_peak_pbn) { // add 0.6% (1006/1000) overhead into effective kbps - effective_kbps *= 1006; - effective_kbps = div_u64(effective_kbps, 1000); - } + link_coding_cap = dc_link_dp_mst_decide_link_encoding_format(dc_link); + if (link_coding_cap == DP_128b_132b_ENCODING) + fec_overhead_multiplier_x1000 = PBN_FEC_OVERHEAD_MULTIPLIER_128B_132B; - return (uint64_t) DIV64_U64_ROUND_UP(effective_kbps * 64, (54 * 8 * 1000)); + return fec_overhead_multiplier_x1000; } -static uint32_t pbn_to_kbps(unsigned int pbn, bool with_margin) +static int kbps_to_peak_pbn(int kbps, uint16_t fec_overhead_multiplier_x1000) { - uint64_t pbn_effective = (uint64_t)pbn; - - if (with_margin) // deduct 0.6% (994/1000) overhead from effective pbn - pbn_effective *= (1000000 / PEAK_FACTOR_X1000); - else - pbn_effective *= 1000; + u64 peak_kbps = kbps; - return DIV_U64_ROUND_UP(pbn_effective * 8 * 54, 64); + peak_kbps *= 1006; + peak_kbps *= fec_overhead_multiplier_x1000; + peak_kbps = div_u64(peak_kbps, 1000 * 1000); + return (int) DIV64_U64_ROUND_UP(peak_kbps * 64, (54 * 8 * 1000)); } static void set_dsc_configs_from_fairness_vars(struct dsc_mst_fairness_params *params, @@ -976,7 +974,7 @@ static int bpp_x16_from_pbn(struct dsc_mst_fairness_params param, int pbn) dc_dsc_get_default_config_option(param.sink->ctx->dc, &dsc_options); dsc_options.max_target_bpp_limit_override_x16 = drm_connector->display_info.max_dsc_bpp * 16; - kbps = pbn_to_kbps(pbn, false); + kbps = div_u64((u64)pbn * 994 * 8 * 54, 64); dc_dsc_compute_config( param.sink->ctx->dc->res_pool->dscs[0], ¶m.sink->dsc_caps.dsc_dec_caps, @@ -1005,11 +1003,12 @@ static int increase_dsc_bpp(struct drm_atomic_state *state, int link_timeslots_used; int fair_pbn_alloc; int ret = 0; + uint16_t fec_overhead_multiplier_x1000 = get_fec_overhead_multiplier(dc_link); for (i = 0; i < count; i++) { if (vars[i + k].dsc_enabled) { initial_slack[i] = - kbps_to_pbn(params[i].bw_range.max_kbps, false) - vars[i + k].pbn; + kbps_to_peak_pbn(params[i].bw_range.max_kbps, fec_overhead_multiplier_x1000) - vars[i + k].pbn; bpp_increased[i] = false; remaining_to_increase += 1; } else { @@ -1105,6 +1104,7 @@ static int try_disable_dsc(struct drm_atomic_state *state, int next_index; int remaining_to_try = 0; int ret; + uint16_t fec_overhead_multiplier_x1000 = get_fec_overhead_multiplier(dc_link); int var_pbn; for (i = 0; i < count; i++) { @@ -1137,7 +1137,7 @@ static int try_disable_dsc(struct drm_atomic_state *state, DRM_DEBUG_DRIVER("MST_DSC index #%d, try no compression\n", next_index); var_pbn = vars[next_index].pbn; - vars[next_index].pbn = kbps_to_pbn(params[next_index].bw_range.stream_kbps, true); + vars[next_index].pbn = kbps_to_peak_pbn(params[next_index].bw_range.stream_kbps, fec_overhead_multiplier_x1000); ret = drm_dp_atomic_find_time_slots(state, params[next_index].port->mgr, params[next_index].port, @@ -1197,6 +1197,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state, int count = 0; int i, k, ret; bool debugfs_overwrite = false; + uint16_t fec_overhead_multiplier_x1000 = get_fec_overhead_multiplier(dc_link); struct drm_connector_state *new_conn_state; memset(params, 0, sizeof(params)); @@ -1277,7 +1278,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state, DRM_DEBUG_DRIVER("MST_DSC Try no compression\n"); for (i = 0; i < count; i++) { vars[i + k].aconnector = params[i].aconnector; - vars[i + k].pbn = kbps_to_pbn(params[i].bw_range.stream_kbps, false); + vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.stream_kbps, fec_overhead_multiplier_x1000); vars[i + k].dsc_enabled = false; vars[i + k].bpp_x16 = 0; ret = drm_dp_atomic_find_time_slots(state, params[i].port->mgr, params[i].port, @@ -1299,7 +1300,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state, DRM_DEBUG_DRIVER("MST_DSC Try max compression\n"); for (i = 0; i < count; i++) { if (params[i].compression_possible && params[i].clock_force_enable != DSC_CLK_FORCE_DISABLE) { - vars[i + k].pbn = kbps_to_pbn(params[i].bw_range.min_kbps, false); + vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.min_kbps, fec_overhead_multiplier_x1000); vars[i + k].dsc_enabled = true; vars[i + k].bpp_x16 = params[i].bw_range.min_target_bpp_x16; ret = drm_dp_atomic_find_time_slots(state, params[i].port->mgr, @@ -1307,7 +1308,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state, if (ret < 0) return ret; } else { - vars[i + k].pbn = kbps_to_pbn(params[i].bw_range.stream_kbps, false); + vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.stream_kbps, fec_overhead_multiplier_x1000); vars[i + k].dsc_enabled = false; vars[i + k].bpp_x16 = 0; ret = drm_dp_atomic_find_time_slots(state, params[i].port->mgr, @@ -1762,6 +1763,18 @@ clean_exit: return ret; } +static uint32_t kbps_from_pbn(unsigned int pbn) +{ + uint64_t kbps = (uint64_t)pbn; + + kbps *= (1000000 / PEAK_FACTOR_X1000); + kbps *= 8; + kbps *= 54; + kbps /= 64; + + return (uint32_t)kbps; +} + static bool is_dsc_common_config_possible(struct dc_stream_state *stream, struct dc_dsc_bw_range *bw_range) { @@ -1860,7 +1873,7 @@ enum dc_status dm_dp_mst_is_port_support_mode( dc_link_get_highest_encoding_format(stream->link)); cur_link_settings = stream->link->verified_link_cap; root_link_bw_in_kbps = dc_link_bandwidth_kbps(aconnector->dc_link, &cur_link_settings); - virtual_channel_bw_in_kbps = pbn_to_kbps(aconnector->mst_output_port->full_pbn, true); + virtual_channel_bw_in_kbps = kbps_from_pbn(aconnector->mst_output_port->full_pbn); /* pick the end to end bw bottleneck */ end_to_end_bw_in_kbps = min(root_link_bw_in_kbps, virtual_channel_bw_in_kbps); @@ -1913,7 +1926,7 @@ enum dc_status dm_dp_mst_is_port_support_mode( immediate_upstream_port = aconnector->mst_output_port->parent->port_parent; if (immediate_upstream_port) { - virtual_channel_bw_in_kbps = pbn_to_kbps(immediate_upstream_port->full_pbn, true); + virtual_channel_bw_in_kbps = kbps_from_pbn(immediate_upstream_port->full_pbn); virtual_channel_bw_in_kbps = min(root_link_bw_in_kbps, virtual_channel_bw_in_kbps); } else { /* For topology LCT 1 case - only one mstb*/ diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_surface.c b/drivers/gpu/drm/amd/display/dc/core/dc_surface.c index 922f23557f5d..0971dfa25845 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_surface.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_surface.c @@ -86,7 +86,7 @@ uint8_t dc_plane_get_pipe_mask(struct dc_state *dc_state, const struct dc_plane struct dc_plane_state *dc_create_plane_state(const struct dc *dc) { struct dc_plane_state *plane_state = kvzalloc(sizeof(*plane_state), - GFP_KERNEL); + GFP_ATOMIC); if (NULL == plane_state) return NULL; diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/display_mode_core.c b/drivers/gpu/drm/amd/display/dc/dml2_0/display_mode_core.c index c468f492b876..09303c282495 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/display_mode_core.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/display_mode_core.c @@ -6711,6 +6711,76 @@ static noinline_for_stack void dml_prefetch_check(struct display_mode_lib_st *mo } // for j } +static noinline_for_stack void set_vm_row_and_swath_parameters(struct display_mode_lib_st *mode_lib) +{ + struct CalculateVMRowAndSwath_params_st *CalculateVMRowAndSwath_params = &mode_lib->scratch.CalculateVMRowAndSwath_params; + struct dml_core_mode_support_locals_st *s = &mode_lib->scratch.dml_core_mode_support_locals; + + CalculateVMRowAndSwath_params->NumberOfActiveSurfaces = mode_lib->ms.num_active_planes; + CalculateVMRowAndSwath_params->myPipe = s->SurfParameters; + CalculateVMRowAndSwath_params->SurfaceSizeInMALL = mode_lib->ms.SurfaceSizeInMALL; + CalculateVMRowAndSwath_params->PTEBufferSizeInRequestsLuma = mode_lib->ms.ip.dpte_buffer_size_in_pte_reqs_luma; + CalculateVMRowAndSwath_params->PTEBufferSizeInRequestsChroma = mode_lib->ms.ip.dpte_buffer_size_in_pte_reqs_chroma; + CalculateVMRowAndSwath_params->DCCMetaBufferSizeBytes = mode_lib->ms.ip.dcc_meta_buffer_size_bytes; + CalculateVMRowAndSwath_params->UseMALLForStaticScreen = mode_lib->ms.cache_display_cfg.plane.UseMALLForStaticScreen; + CalculateVMRowAndSwath_params->UseMALLForPStateChange = mode_lib->ms.cache_display_cfg.plane.UseMALLForPStateChange; + CalculateVMRowAndSwath_params->MALLAllocatedForDCN = mode_lib->ms.soc.mall_allocated_for_dcn_mbytes; + CalculateVMRowAndSwath_params->SwathWidthY = mode_lib->ms.SwathWidthYThisState; + CalculateVMRowAndSwath_params->SwathWidthC = mode_lib->ms.SwathWidthCThisState; + CalculateVMRowAndSwath_params->GPUVMEnable = mode_lib->ms.cache_display_cfg.plane.GPUVMEnable; + CalculateVMRowAndSwath_params->HostVMEnable = mode_lib->ms.cache_display_cfg.plane.HostVMEnable; + CalculateVMRowAndSwath_params->HostVMMaxNonCachedPageTableLevels = mode_lib->ms.cache_display_cfg.plane.HostVMMaxPageTableLevels; + CalculateVMRowAndSwath_params->GPUVMMaxPageTableLevels = mode_lib->ms.cache_display_cfg.plane.GPUVMMaxPageTableLevels; + CalculateVMRowAndSwath_params->GPUVMMinPageSizeKBytes = mode_lib->ms.cache_display_cfg.plane.GPUVMMinPageSizeKBytes; + CalculateVMRowAndSwath_params->HostVMMinPageSize = mode_lib->ms.soc.hostvm_min_page_size_kbytes * 1024; + CalculateVMRowAndSwath_params->PTEBufferModeOverrideEn = mode_lib->ms.cache_display_cfg.plane.PTEBufferModeOverrideEn; + CalculateVMRowAndSwath_params->PTEBufferModeOverrideVal = mode_lib->ms.cache_display_cfg.plane.PTEBufferMode; + CalculateVMRowAndSwath_params->PTEBufferSizeNotExceeded = mode_lib->ms.PTEBufferSizeNotExceededPerState; + CalculateVMRowAndSwath_params->DCCMetaBufferSizeNotExceeded = mode_lib->ms.DCCMetaBufferSizeNotExceededPerState; + CalculateVMRowAndSwath_params->dpte_row_width_luma_ub = s->dummy_integer_array[0]; + CalculateVMRowAndSwath_params->dpte_row_width_chroma_ub = s->dummy_integer_array[1]; + CalculateVMRowAndSwath_params->dpte_row_height_luma = mode_lib->ms.dpte_row_height; + CalculateVMRowAndSwath_params->dpte_row_height_chroma = mode_lib->ms.dpte_row_height_chroma; + CalculateVMRowAndSwath_params->dpte_row_height_linear_luma = s->dummy_integer_array[2]; // VBA_DELTA + CalculateVMRowAndSwath_params->dpte_row_height_linear_chroma = s->dummy_integer_array[3]; // VBA_DELTA + CalculateVMRowAndSwath_params->meta_req_width = s->dummy_integer_array[4]; + CalculateVMRowAndSwath_params->meta_req_width_chroma = s->dummy_integer_array[5]; + CalculateVMRowAndSwath_params->meta_req_height = s->dummy_integer_array[6]; + CalculateVMRowAndSwath_params->meta_req_height_chroma = s->dummy_integer_array[7]; + CalculateVMRowAndSwath_params->meta_row_width = s->dummy_integer_array[8]; + CalculateVMRowAndSwath_params->meta_row_width_chroma = s->dummy_integer_array[9]; + CalculateVMRowAndSwath_params->meta_row_height = mode_lib->ms.meta_row_height; + CalculateVMRowAndSwath_params->meta_row_height_chroma = mode_lib->ms.meta_row_height_chroma; + CalculateVMRowAndSwath_params->vm_group_bytes = s->dummy_integer_array[10]; + CalculateVMRowAndSwath_params->dpte_group_bytes = mode_lib->ms.dpte_group_bytes; + CalculateVMRowAndSwath_params->PixelPTEReqWidthY = s->dummy_integer_array[11]; + CalculateVMRowAndSwath_params->PixelPTEReqHeightY = s->dummy_integer_array[12]; + CalculateVMRowAndSwath_params->PTERequestSizeY = s->dummy_integer_array[13]; + CalculateVMRowAndSwath_params->PixelPTEReqWidthC = s->dummy_integer_array[14]; + CalculateVMRowAndSwath_params->PixelPTEReqHeightC = s->dummy_integer_array[15]; + CalculateVMRowAndSwath_params->PTERequestSizeC = s->dummy_integer_array[16]; + CalculateVMRowAndSwath_params->dpde0_bytes_per_frame_ub_l = s->dummy_integer_array[17]; + CalculateVMRowAndSwath_params->meta_pte_bytes_per_frame_ub_l = s->dummy_integer_array[18]; + CalculateVMRowAndSwath_params->dpde0_bytes_per_frame_ub_c = s->dummy_integer_array[19]; + CalculateVMRowAndSwath_params->meta_pte_bytes_per_frame_ub_c = s->dummy_integer_array[20]; + CalculateVMRowAndSwath_params->PrefetchSourceLinesY = mode_lib->ms.PrefetchLinesYThisState; + CalculateVMRowAndSwath_params->PrefetchSourceLinesC = mode_lib->ms.PrefetchLinesCThisState; + CalculateVMRowAndSwath_params->VInitPreFillY = mode_lib->ms.PrefillY; + CalculateVMRowAndSwath_params->VInitPreFillC = mode_lib->ms.PrefillC; + CalculateVMRowAndSwath_params->MaxNumSwathY = mode_lib->ms.MaxNumSwY; + CalculateVMRowAndSwath_params->MaxNumSwathC = mode_lib->ms.MaxNumSwC; + CalculateVMRowAndSwath_params->meta_row_bw = mode_lib->ms.meta_row_bandwidth_this_state; + CalculateVMRowAndSwath_params->dpte_row_bw = mode_lib->ms.dpte_row_bandwidth_this_state; + CalculateVMRowAndSwath_params->PixelPTEBytesPerRow = mode_lib->ms.DPTEBytesPerRowThisState; + CalculateVMRowAndSwath_params->PDEAndMetaPTEBytesFrame = mode_lib->ms.PDEAndMetaPTEBytesPerFrameThisState; + CalculateVMRowAndSwath_params->MetaRowByte = mode_lib->ms.MetaRowBytesThisState; + CalculateVMRowAndSwath_params->use_one_row_for_frame = mode_lib->ms.use_one_row_for_frame_this_state; + CalculateVMRowAndSwath_params->use_one_row_for_frame_flip = mode_lib->ms.use_one_row_for_frame_flip_this_state; + CalculateVMRowAndSwath_params->UsesMALLForStaticScreen = s->dummy_boolean_array[0]; + CalculateVMRowAndSwath_params->PTE_BUFFER_MODE = s->dummy_boolean_array[1]; + CalculateVMRowAndSwath_params->BIGK_FRAGMENT_SIZE = s->dummy_integer_array[21]; +} + /// @brief The Mode Support function. dml_bool_t dml_core_mode_support(struct display_mode_lib_st *mode_lib) { @@ -7683,69 +7753,7 @@ dml_bool_t dml_core_mode_support(struct display_mode_lib_st *mode_lib) s->SurfParameters[k].SwathHeightC = mode_lib->ms.SwathHeightCThisState[k]; } - CalculateVMRowAndSwath_params->NumberOfActiveSurfaces = mode_lib->ms.num_active_planes; - CalculateVMRowAndSwath_params->myPipe = s->SurfParameters; - CalculateVMRowAndSwath_params->SurfaceSizeInMALL = mode_lib->ms.SurfaceSizeInMALL; - CalculateVMRowAndSwath_params->PTEBufferSizeInRequestsLuma = mode_lib->ms.ip.dpte_buffer_size_in_pte_reqs_luma; - CalculateVMRowAndSwath_params->PTEBufferSizeInRequestsChroma = mode_lib->ms.ip.dpte_buffer_size_in_pte_reqs_chroma; - CalculateVMRowAndSwath_params->DCCMetaBufferSizeBytes = mode_lib->ms.ip.dcc_meta_buffer_size_bytes; - CalculateVMRowAndSwath_params->UseMALLForStaticScreen = mode_lib->ms.cache_display_cfg.plane.UseMALLForStaticScreen; - CalculateVMRowAndSwath_params->UseMALLForPStateChange = mode_lib->ms.cache_display_cfg.plane.UseMALLForPStateChange; - CalculateVMRowAndSwath_params->MALLAllocatedForDCN = mode_lib->ms.soc.mall_allocated_for_dcn_mbytes; - CalculateVMRowAndSwath_params->SwathWidthY = mode_lib->ms.SwathWidthYThisState; - CalculateVMRowAndSwath_params->SwathWidthC = mode_lib->ms.SwathWidthCThisState; - CalculateVMRowAndSwath_params->GPUVMEnable = mode_lib->ms.cache_display_cfg.plane.GPUVMEnable; - CalculateVMRowAndSwath_params->HostVMEnable = mode_lib->ms.cache_display_cfg.plane.HostVMEnable; - CalculateVMRowAndSwath_params->HostVMMaxNonCachedPageTableLevels = mode_lib->ms.cache_display_cfg.plane.HostVMMaxPageTableLevels; - CalculateVMRowAndSwath_params->GPUVMMaxPageTableLevels = mode_lib->ms.cache_display_cfg.plane.GPUVMMaxPageTableLevels; - CalculateVMRowAndSwath_params->GPUVMMinPageSizeKBytes = mode_lib->ms.cache_display_cfg.plane.GPUVMMinPageSizeKBytes; - CalculateVMRowAndSwath_params->HostVMMinPageSize = mode_lib->ms.soc.hostvm_min_page_size_kbytes * 1024; - CalculateVMRowAndSwath_params->PTEBufferModeOverrideEn = mode_lib->ms.cache_display_cfg.plane.PTEBufferModeOverrideEn; - CalculateVMRowAndSwath_params->PTEBufferModeOverrideVal = mode_lib->ms.cache_display_cfg.plane.PTEBufferMode; - CalculateVMRowAndSwath_params->PTEBufferSizeNotExceeded = mode_lib->ms.PTEBufferSizeNotExceededPerState; - CalculateVMRowAndSwath_params->DCCMetaBufferSizeNotExceeded = mode_lib->ms.DCCMetaBufferSizeNotExceededPerState; - CalculateVMRowAndSwath_params->dpte_row_width_luma_ub = s->dummy_integer_array[0]; - CalculateVMRowAndSwath_params->dpte_row_width_chroma_ub = s->dummy_integer_array[1]; - CalculateVMRowAndSwath_params->dpte_row_height_luma = mode_lib->ms.dpte_row_height; - CalculateVMRowAndSwath_params->dpte_row_height_chroma = mode_lib->ms.dpte_row_height_chroma; - CalculateVMRowAndSwath_params->dpte_row_height_linear_luma = s->dummy_integer_array[2]; // VBA_DELTA - CalculateVMRowAndSwath_params->dpte_row_height_linear_chroma = s->dummy_integer_array[3]; // VBA_DELTA - CalculateVMRowAndSwath_params->meta_req_width = s->dummy_integer_array[4]; - CalculateVMRowAndSwath_params->meta_req_width_chroma = s->dummy_integer_array[5]; - CalculateVMRowAndSwath_params->meta_req_height = s->dummy_integer_array[6]; - CalculateVMRowAndSwath_params->meta_req_height_chroma = s->dummy_integer_array[7]; - CalculateVMRowAndSwath_params->meta_row_width = s->dummy_integer_array[8]; - CalculateVMRowAndSwath_params->meta_row_width_chroma = s->dummy_integer_array[9]; - CalculateVMRowAndSwath_params->meta_row_height = mode_lib->ms.meta_row_height; - CalculateVMRowAndSwath_params->meta_row_height_chroma = mode_lib->ms.meta_row_height_chroma; - CalculateVMRowAndSwath_params->vm_group_bytes = s->dummy_integer_array[10]; - CalculateVMRowAndSwath_params->dpte_group_bytes = mode_lib->ms.dpte_group_bytes; - CalculateVMRowAndSwath_params->PixelPTEReqWidthY = s->dummy_integer_array[11]; - CalculateVMRowAndSwath_params->PixelPTEReqHeightY = s->dummy_integer_array[12]; - CalculateVMRowAndSwath_params->PTERequestSizeY = s->dummy_integer_array[13]; - CalculateVMRowAndSwath_params->PixelPTEReqWidthC = s->dummy_integer_array[14]; - CalculateVMRowAndSwath_params->PixelPTEReqHeightC = s->dummy_integer_array[15]; - CalculateVMRowAndSwath_params->PTERequestSizeC = s->dummy_integer_array[16]; - CalculateVMRowAndSwath_params->dpde0_bytes_per_frame_ub_l = s->dummy_integer_array[17]; - CalculateVMRowAndSwath_params->meta_pte_bytes_per_frame_ub_l = s->dummy_integer_array[18]; - CalculateVMRowAndSwath_params->dpde0_bytes_per_frame_ub_c = s->dummy_integer_array[19]; - CalculateVMRowAndSwath_params->meta_pte_bytes_per_frame_ub_c = s->dummy_integer_array[20]; - CalculateVMRowAndSwath_params->PrefetchSourceLinesY = mode_lib->ms.PrefetchLinesYThisState; - CalculateVMRowAndSwath_params->PrefetchSourceLinesC = mode_lib->ms.PrefetchLinesCThisState; - CalculateVMRowAndSwath_params->VInitPreFillY = mode_lib->ms.PrefillY; - CalculateVMRowAndSwath_params->VInitPreFillC = mode_lib->ms.PrefillC; - CalculateVMRowAndSwath_params->MaxNumSwathY = mode_lib->ms.MaxNumSwY; - CalculateVMRowAndSwath_params->MaxNumSwathC = mode_lib->ms.MaxNumSwC; - CalculateVMRowAndSwath_params->meta_row_bw = mode_lib->ms.meta_row_bandwidth_this_state; - CalculateVMRowAndSwath_params->dpte_row_bw = mode_lib->ms.dpte_row_bandwidth_this_state; - CalculateVMRowAndSwath_params->PixelPTEBytesPerRow = mode_lib->ms.DPTEBytesPerRowThisState; - CalculateVMRowAndSwath_params->PDEAndMetaPTEBytesFrame = mode_lib->ms.PDEAndMetaPTEBytesPerFrameThisState; - CalculateVMRowAndSwath_params->MetaRowByte = mode_lib->ms.MetaRowBytesThisState; - CalculateVMRowAndSwath_params->use_one_row_for_frame = mode_lib->ms.use_one_row_for_frame_this_state; - CalculateVMRowAndSwath_params->use_one_row_for_frame_flip = mode_lib->ms.use_one_row_for_frame_flip_this_state; - CalculateVMRowAndSwath_params->UsesMALLForStaticScreen = s->dummy_boolean_array[0]; - CalculateVMRowAndSwath_params->PTE_BUFFER_MODE = s->dummy_boolean_array[1]; - CalculateVMRowAndSwath_params->BIGK_FRAGMENT_SIZE = s->dummy_integer_array[21]; + set_vm_row_and_swath_parameters(mode_lib); CalculateVMRowAndSwath(&mode_lib->scratch, CalculateVMRowAndSwath_params); diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c index 8fe399939220..4986f12dc9df 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c @@ -1484,9 +1484,6 @@ void build_audio_output( state->clk_mgr); } - audio_output->pll_info.feed_back_divider = - pipe_ctx->pll_settings.feedback_divider; - audio_output->pll_info.dto_source = translate_to_dto_source( pipe_ctx->stream_res.tg->inst + 1); diff --git a/drivers/gpu/drm/amd/display/include/audio_types.h b/drivers/gpu/drm/amd/display/include/audio_types.h index e4a26143f14c..6699ad4fa825 100644 --- a/drivers/gpu/drm/amd/display/include/audio_types.h +++ b/drivers/gpu/drm/amd/display/include/audio_types.h @@ -47,15 +47,15 @@ struct audio_crtc_info { uint32_t h_total; uint32_t h_active; uint32_t v_active; - uint32_t pixel_repetition; uint32_t requested_pixel_clock_100Hz; /* in 100Hz */ uint32_t calculated_pixel_clock_100Hz; /* in 100Hz */ - uint32_t refresh_rate; + uint32_t dsc_bits_per_pixel; + uint32_t dsc_num_slices; enum dc_color_depth color_depth; enum dc_pixel_encoding pixel_encoding; + uint16_t refresh_rate; + uint8_t pixel_repetition; bool interlaced; - uint32_t dsc_bits_per_pixel; - uint32_t dsc_num_slices; }; struct azalia_clock_info { uint32_t pixel_clock_in_10khz; @@ -78,11 +78,9 @@ enum audio_dto_source { struct audio_pll_info { uint32_t audio_dto_source_clock_in_khz; - uint32_t feed_back_divider; + uint32_t ss_percentage; enum audio_dto_source dto_source; bool ss_enabled; - uint32_t ss_percentage; - uint32_t ss_percentage_divider; }; struct audio_channel_associate_info { diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi83.c b/drivers/gpu/drm/bridge/ti-sn65dsi83.c index 033c44326552..fffb47b62f43 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi83.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi83.c @@ -429,7 +429,14 @@ static void sn65dsi83_handle_errors(struct sn65dsi83 *ctx) */ ret = regmap_read(ctx->regmap, REG_IRQ_STAT, &irq_stat); - if (ret || irq_stat) { + + /* + * Some hardware (Toradex Verdin AM62) is known to report the + * PLL_UNLOCK error interrupt while working without visible + * problems. In lack of a reliable way to discriminate such cases + * from user-visible PLL_UNLOCK cases, ignore that bit entirely. + */ + if (ret || irq_stat & ~REG_IRQ_STAT_CHA_PLL_UNLOCK) { /* * IRQ acknowledged is not always possible (the bridge can be in * a state where it doesn't answer anymore). To prevent an @@ -654,7 +661,7 @@ static void sn65dsi83_atomic_enable(struct drm_bridge *bridge, if (ctx->irq) { /* Enable irq to detect errors */ regmap_write(ctx->regmap, REG_IRQ_GLOBAL, REG_IRQ_GLOBAL_IRQ_EN); - regmap_write(ctx->regmap, REG_IRQ_EN, 0xff); + regmap_write(ctx->regmap, REG_IRQ_EN, 0xff & ~REG_IRQ_EN_CHA_PLL_UNLOCK_EN); } else { /* Use the polling task */ sn65dsi83_monitor_start(ctx); diff --git a/drivers/gpu/drm/drm_gem_dma_helper.c b/drivers/gpu/drm/drm_gem_dma_helper.c index 12d8307997a0..eb56ba234796 100644 --- a/drivers/gpu/drm/drm_gem_dma_helper.c +++ b/drivers/gpu/drm/drm_gem_dma_helper.c @@ -308,7 +308,7 @@ int drm_gem_dma_dumb_create(struct drm_file *file_priv, struct drm_gem_dma_object *dma_obj; int ret; - ret = drm_mode_size_dumb(drm, args, SZ_8, 0); + ret = drm_mode_size_dumb(drm, args, 0, 0); if (ret) return ret; diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c index dc94a27710e5..93b9cff89080 100644 --- a/drivers/gpu/drm/drm_gem_shmem_helper.c +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c @@ -559,7 +559,7 @@ int drm_gem_shmem_dumb_create(struct drm_file *file, struct drm_device *dev, { int ret; - ret = drm_mode_size_dumb(dev, args, SZ_8, 0); + ret = drm_mode_size_dumb(dev, args, 0, 0); if (ret) return ret; diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index ce76c55913f7..b143589717e6 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -338,14 +338,14 @@ static int drm_plane_create_hotspot_properties(struct drm_plane *plane) prop_x = drm_property_create_signed_range(plane->dev, 0, "HOTSPOT_X", INT_MIN, INT_MAX); - if (IS_ERR(prop_x)) - return PTR_ERR(prop_x); + if (!prop_x) + return -ENOMEM; prop_y = drm_property_create_signed_range(plane->dev, 0, "HOTSPOT_Y", INT_MIN, INT_MAX); - if (IS_ERR(prop_y)) { + if (!prop_y) { drm_property_destroy(plane->dev, prop_x); - return PTR_ERR(prop_y); + return -ENOMEM; } drm_object_attach_property(&plane->base, prop_x, 0); diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c index 9cd03e2adeb2..44f4fcce526e 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev.c @@ -288,13 +288,18 @@ int intel_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper, drm_framebuffer_put(&fb->base); fb = NULL; } + + wakeref = intel_display_rpm_get(display); + if (!fb || drm_WARN_ON(display->drm, !intel_fb_bo(&fb->base))) { drm_dbg_kms(display->drm, "no BIOS fb, allocating a new one\n"); fb = __intel_fbdev_fb_alloc(display, sizes); - if (IS_ERR(fb)) - return PTR_ERR(fb); + if (IS_ERR(fb)) { + ret = PTR_ERR(fb); + goto out_unlock; + } } else { drm_dbg_kms(display->drm, "re-using BIOS fb\n"); prealloc = true; @@ -302,8 +307,6 @@ int intel_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper, sizes->fb_height = fb->base.height; } - wakeref = intel_display_rpm_get(display); - /* Pin the GGTT vma for our access via info->screen_base. * This also validates that any existing fb inherited from the * BIOS is suitable for own access. diff --git a/drivers/gpu/drm/i915/intel_memory_region.h b/drivers/gpu/drm/i915/intel_memory_region.h index b3b75be9ced5..e9a4e6090fe0 100644 --- a/drivers/gpu/drm/i915/intel_memory_region.h +++ b/drivers/gpu/drm/i915/intel_memory_region.h @@ -72,7 +72,7 @@ struct intel_memory_region { u16 instance; enum intel_region_id id; char name[16]; - char uabi_name[16]; + char uabi_name[20]; bool private; /* not for userspace */ struct { diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 951d715dea30..d019177462cf 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -161,6 +161,30 @@ static void mgag200_set_startadd(struct mga_device *mdev, WREG_ECRT(0x00, crtcext0); } +/* + * Set the opmode for the hardware swapper for Big-Endian processor + * support for the frame buffer aperture and DMAWIN space. + */ +static void mgag200_set_datasiz(struct mga_device *mdev, u32 format) +{ +#if defined(__BIG_ENDIAN) + u32 opmode = RREG32(MGAREG_OPMODE); + + opmode &= ~(GENMASK(17, 16) | GENMASK(9, 8) | GENMASK(3, 2)); + + /* Big-endian byte-swapping */ + switch (format) { + case DRM_FORMAT_RGB565: + opmode |= 0x10100; + break; + case DRM_FORMAT_XRGB8888: + opmode |= 0x20200; + break; + } + WREG32(MGAREG_OPMODE, opmode); +#endif +} + void mgag200_init_registers(struct mga_device *mdev) { u8 crtc11, misc; @@ -496,6 +520,7 @@ void mgag200_primary_plane_helper_atomic_update(struct drm_plane *plane, struct drm_atomic_helper_damage_iter iter; struct drm_rect damage; + mgag200_set_datasiz(mdev, fb->format->format); drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state); drm_atomic_for_each_plane_damage(&iter, &damage) { mgag200_handle_damage(mdev, shadow_plane_state->data, fb, &damage); diff --git a/drivers/gpu/drm/nouveau/dispnv04/nouveau_i2c_encoder.c b/drivers/gpu/drm/nouveau/dispnv04/nouveau_i2c_encoder.c index e2bf99c43336..a60209097a20 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/nouveau_i2c_encoder.c +++ b/drivers/gpu/drm/nouveau/dispnv04/nouveau_i2c_encoder.c @@ -94,26 +94,6 @@ fail_unregister: return err; } -/** - * nouveau_i2c_encoder_destroy - Unregister the I2C device backing an encoder - * @drm_encoder: Encoder to be unregistered. - * - * This should be called from the @destroy method of an I2C slave - * encoder driver once I2C access is no longer needed. - */ -void nouveau_i2c_encoder_destroy(struct drm_encoder *drm_encoder) -{ - struct nouveau_i2c_encoder *encoder = to_encoder_i2c(drm_encoder); - struct i2c_client *client = nouveau_i2c_encoder_get_client(drm_encoder); - struct module *module = client->dev.driver->owner; - - i2c_unregister_device(client); - encoder->i2c_client = NULL; - - module_put(module); -} -EXPORT_SYMBOL(nouveau_i2c_encoder_destroy); - /* * Wrapper fxns which can be plugged in to drm_encoder_helper_funcs: */ diff --git a/drivers/gpu/drm/nouveau/include/dispnv04/i2c/encoder_i2c.h b/drivers/gpu/drm/nouveau/include/dispnv04/i2c/encoder_i2c.h index 31334aa90781..869820701a56 100644 --- a/drivers/gpu/drm/nouveau/include/dispnv04/i2c/encoder_i2c.h +++ b/drivers/gpu/drm/nouveau/include/dispnv04/i2c/encoder_i2c.h @@ -202,7 +202,24 @@ static inline struct i2c_client *nouveau_i2c_encoder_get_client(struct drm_encod return to_encoder_i2c(encoder)->i2c_client; } -void nouveau_i2c_encoder_destroy(struct drm_encoder *encoder); +/** + * nouveau_i2c_encoder_destroy - Unregister the I2C device backing an encoder + * @drm_encoder: Encoder to be unregistered. + * + * This should be called from the @destroy method of an I2C slave + * encoder driver once I2C access is no longer needed. + */ +static __always_inline void nouveau_i2c_encoder_destroy(struct drm_encoder *drm_encoder) +{ + struct nouveau_i2c_encoder *encoder = to_encoder_i2c(drm_encoder); + struct i2c_client *client = nouveau_i2c_encoder_get_client(drm_encoder); + struct module *module = client->dev.driver->owner; + + i2c_unregister_device(client); + encoder->i2c_client = NULL; + + module_put(module); +} /* * Wrapper fxns which can be plugged in to drm_encoder_helper_funcs: diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h index 226c7ec56b8e..b8b97e10ae83 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h @@ -73,6 +73,10 @@ struct nvkm_gsp { const struct firmware *bl; const struct firmware *rm; + + struct { + struct nvkm_falcon_fw sb; + } falcon; } fws; struct nvkm_firmware fw; diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 869d4335c0f4..4a193b7d6d9e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -183,11 +183,11 @@ nouveau_fence_context_new(struct nouveau_channel *chan, struct nouveau_fence_cha fctx->context = drm->runl[chan->runlist].context_base + chan->chid; if (chan == drm->cechan) - strcpy(fctx->name, "copy engine channel"); + strscpy(fctx->name, "copy engine channel"); else if (chan == drm->channel) - strcpy(fctx->name, "generic kernel channel"); + strscpy(fctx->name, "generic kernel channel"); else - strcpy(fctx->name, cli->name); + strscpy(fctx->name, cli->name); kref_init(&fctx->fence_ref); if (!priv->uevent) diff --git a/drivers/gpu/drm/nouveau/nouveau_hwmon.c b/drivers/gpu/drm/nouveau/nouveau_hwmon.c index 5c07a9ee8b77..34effe6d86ad 100644 --- a/drivers/gpu/drm/nouveau/nouveau_hwmon.c +++ b/drivers/gpu/drm/nouveau/nouveau_hwmon.c @@ -125,7 +125,7 @@ nouveau_hwmon_get_pwm1_max(struct device *d, if (ret < 0) return ret; - return sprintf(buf, "%i\n", ret); + return sysfs_emit(buf, "%i\n", ret); } static ssize_t @@ -141,7 +141,7 @@ nouveau_hwmon_get_pwm1_min(struct device *d, if (ret < 0) return ret; - return sprintf(buf, "%i\n", ret); + return sysfs_emit(buf, "%i\n", ret); } static ssize_t diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/fwsec.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/fwsec.c index 5b721bd9d799..503760246660 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/fwsec.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/fwsec.c @@ -259,18 +259,16 @@ nvkm_gsp_fwsec_v3(struct nvkm_gsp *gsp, const char *name, } static int -nvkm_gsp_fwsec(struct nvkm_gsp *gsp, const char *name, u32 init_cmd) +nvkm_gsp_fwsec_init(struct nvkm_gsp *gsp, struct nvkm_falcon_fw *fw, const char *name, u32 init_cmd) { struct nvkm_subdev *subdev = &gsp->subdev; struct nvkm_device *device = subdev->device; struct nvkm_bios *bios = device->bios; const union nvfw_falcon_ucode_desc *desc; struct nvbios_pmuE flcn_ucode; - u8 idx, ver, hdr; u32 data; u16 size, vers; - struct nvkm_falcon_fw fw = {}; - u32 mbox0 = 0; + u8 idx, ver, hdr; int ret; /* Lookup in VBIOS. */ @@ -291,8 +289,8 @@ nvkm_gsp_fwsec(struct nvkm_gsp *gsp, const char *name, u32 init_cmd) vers = (desc->v2.Hdr & 0x0000ff00) >> 8; switch (vers) { - case 2: ret = nvkm_gsp_fwsec_v2(gsp, name, &desc->v2, size, init_cmd, &fw); break; - case 3: ret = nvkm_gsp_fwsec_v3(gsp, name, &desc->v3, size, init_cmd, &fw); break; + case 2: ret = nvkm_gsp_fwsec_v2(gsp, name, &desc->v2, size, init_cmd, fw); break; + case 3: ret = nvkm_gsp_fwsec_v3(gsp, name, &desc->v3, size, init_cmd, fw); break; default: nvkm_error(subdev, "%s(v%d): version unknown\n", name, vers); return -EINVAL; @@ -303,15 +301,19 @@ nvkm_gsp_fwsec(struct nvkm_gsp *gsp, const char *name, u32 init_cmd) return ret; } - /* Boot. */ - ret = nvkm_falcon_fw_boot(&fw, subdev, true, &mbox0, NULL, 0, 0); - nvkm_falcon_fw_dtor(&fw); - if (ret) - return ret; - return 0; } +static int +nvkm_gsp_fwsec_boot(struct nvkm_gsp *gsp, struct nvkm_falcon_fw *fw) +{ + struct nvkm_subdev *subdev = &gsp->subdev; + u32 mbox0 = 0; + + /* Boot */ + return nvkm_falcon_fw_boot(fw, subdev, true, &mbox0, NULL, 0, 0); +} + int nvkm_gsp_fwsec_sb(struct nvkm_gsp *gsp) { @@ -320,7 +322,7 @@ nvkm_gsp_fwsec_sb(struct nvkm_gsp *gsp) int ret; u32 err; - ret = nvkm_gsp_fwsec(gsp, "fwsec-sb", NVFW_FALCON_APPIF_DMEMMAPPER_CMD_SB); + ret = nvkm_gsp_fwsec_boot(gsp, &gsp->fws.falcon.sb); if (ret) return ret; @@ -335,26 +337,47 @@ nvkm_gsp_fwsec_sb(struct nvkm_gsp *gsp) } int +nvkm_gsp_fwsec_sb_ctor(struct nvkm_gsp *gsp) +{ + return nvkm_gsp_fwsec_init(gsp, &gsp->fws.falcon.sb, "fwsec-sb", + NVFW_FALCON_APPIF_DMEMMAPPER_CMD_SB); +} + +void +nvkm_gsp_fwsec_sb_dtor(struct nvkm_gsp *gsp) +{ + nvkm_falcon_fw_dtor(&gsp->fws.falcon.sb); +} + +int nvkm_gsp_fwsec_frts(struct nvkm_gsp *gsp) { struct nvkm_subdev *subdev = &gsp->subdev; struct nvkm_device *device = subdev->device; + struct nvkm_falcon_fw fw = {}; int ret; u32 err, wpr2_lo, wpr2_hi; - ret = nvkm_gsp_fwsec(gsp, "fwsec-frts", NVFW_FALCON_APPIF_DMEMMAPPER_CMD_FRTS); + ret = nvkm_gsp_fwsec_init(gsp, &fw, "fwsec-frts", NVFW_FALCON_APPIF_DMEMMAPPER_CMD_FRTS); if (ret) return ret; + ret = nvkm_gsp_fwsec_boot(gsp, &fw); + if (ret) + goto fwsec_dtor; + /* Verify. */ err = nvkm_rd32(device, 0x001400 + (0xe * 4)) >> 16; if (err) { nvkm_error(subdev, "fwsec-frts: 0x%04x\n", err); - return -EIO; + ret = -EIO; + } else { + wpr2_lo = nvkm_rd32(device, 0x1fa824); + wpr2_hi = nvkm_rd32(device, 0x1fa828); + nvkm_debug(subdev, "fwsec-frts: WPR2 @ %08x - %08x\n", wpr2_lo, wpr2_hi); } - wpr2_lo = nvkm_rd32(device, 0x1fa824); - wpr2_hi = nvkm_rd32(device, 0x1fa828); - nvkm_debug(subdev, "fwsec-frts: WPR2 @ %08x - %08x\n", wpr2_lo, wpr2_hi); - return 0; +fwsec_dtor: + nvkm_falcon_fw_dtor(&fw); + return ret; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h index c3494b7ac572..86bdd203bc10 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h @@ -6,7 +6,10 @@ enum nvkm_acr_lsf_id; int nvkm_gsp_fwsec_frts(struct nvkm_gsp *); + +int nvkm_gsp_fwsec_sb_ctor(struct nvkm_gsp *); int nvkm_gsp_fwsec_sb(struct nvkm_gsp *); +void nvkm_gsp_fwsec_sb_dtor(struct nvkm_gsp *); struct nvkm_gsp_fwif { int version; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c index 32e6a065d6d7..2a7e80c6d70f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c @@ -1817,12 +1817,16 @@ r535_gsp_rm_boot_ctor(struct nvkm_gsp *gsp) RM_RISCV_UCODE_DESC *desc; int ret; + ret = nvkm_gsp_fwsec_sb_ctor(gsp); + if (ret) + return ret; + hdr = nvfw_bin_hdr(&gsp->subdev, fw->data); desc = (void *)fw->data + hdr->header_offset; ret = nvkm_gsp_mem_ctor(gsp, hdr->data_size, &gsp->boot.fw); if (ret) - return ret; + goto dtor_fwsec; memcpy(gsp->boot.fw.data, fw->data + hdr->data_offset, hdr->data_size); @@ -1831,6 +1835,9 @@ r535_gsp_rm_boot_ctor(struct nvkm_gsp *gsp) gsp->boot.manifest_offset = desc->manifestOffset; gsp->boot.app_version = desc->appVersion; return 0; +dtor_fwsec: + nvkm_gsp_fwsec_sb_dtor(gsp); + return ret; } static const struct nvkm_firmware_func @@ -2101,6 +2108,7 @@ r535_gsp_dtor(struct nvkm_gsp *gsp) mutex_destroy(&gsp->cmdq.mutex); nvkm_gsp_dtor_fws(gsp); + nvkm_gsp_fwsec_sb_dtor(gsp); nvkm_gsp_mem_dtor(&gsp->rmargs); nvkm_gsp_mem_dtor(&gsp->wpr_meta); diff --git a/drivers/gpu/drm/panel/panel-novatek-nt35560.c b/drivers/gpu/drm/panel/panel-novatek-nt35560.c index 561e6643dcbb..6e5173f98a22 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt35560.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt35560.c @@ -213,7 +213,7 @@ static const struct backlight_properties nt35560_bl_props = { static void nt35560_read_id(struct mipi_dsi_multi_context *dsi_ctx) { - struct device dev = dsi_ctx->dsi->dev; + struct device *dev = &dsi_ctx->dsi->dev; u8 vendor, version, panel; u16 val; @@ -225,7 +225,7 @@ static void nt35560_read_id(struct mipi_dsi_multi_context *dsi_ctx) return; if (vendor == 0x00) { - dev_err(&dev, "device vendor ID is zero\n"); + dev_err(dev, "device vendor ID is zero\n"); dsi_ctx->accum_err = -ENODEV; return; } @@ -236,12 +236,12 @@ static void nt35560_read_id(struct mipi_dsi_multi_context *dsi_ctx) case DISPLAY_SONY_ACX424AKP_ID2: case DISPLAY_SONY_ACX424AKP_ID3: case DISPLAY_SONY_ACX424AKP_ID4: - dev_info(&dev, + dev_info(dev, "MTP vendor: %02x, version: %02x, panel: %02x\n", vendor, version, panel); break; default: - dev_info(&dev, + dev_info(dev, "unknown vendor: %02x, version: %02x, panel: %02x\n", vendor, version, panel); break; diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c index b834123a6560..a6b8024e1a3c 100644 --- a/drivers/gpu/drm/panthor/panthor_sched.c +++ b/drivers/gpu/drm/panthor/panthor_sched.c @@ -779,6 +779,12 @@ struct panthor_job_profiling_data { */ #define MAX_GROUPS_PER_POOL 128 +/* + * Mark added on an entry of group pool Xarray to identify if the group has + * been fully initialized and can be accessed elsewhere in the driver code. + */ +#define GROUP_REGISTERED XA_MARK_1 + /** * struct panthor_group_pool - Group pool * @@ -3007,7 +3013,7 @@ void panthor_fdinfo_gather_group_samples(struct panthor_file *pfile) return; xa_lock(&gpool->xa); - xa_for_each(&gpool->xa, i, group) { + xa_for_each_marked(&gpool->xa, i, group, GROUP_REGISTERED) { guard(spinlock)(&group->fdinfo.lock); pfile->stats.cycles += group->fdinfo.data.cycles; pfile->stats.time += group->fdinfo.data.time; @@ -3727,6 +3733,8 @@ int panthor_group_create(struct panthor_file *pfile, group_init_task_info(group); + xa_set_mark(&gpool->xa, gid, GROUP_REGISTERED); + return gid; err_erase_gid: @@ -3744,6 +3752,9 @@ int panthor_group_destroy(struct panthor_file *pfile, u32 group_handle) struct panthor_scheduler *sched = ptdev->scheduler; struct panthor_group *group; + if (!xa_get_mark(&gpool->xa, group_handle, GROUP_REGISTERED)) + return -EINVAL; + group = xa_erase(&gpool->xa, group_handle); if (!group) return -EINVAL; @@ -3769,12 +3780,12 @@ int panthor_group_destroy(struct panthor_file *pfile, u32 group_handle) } static struct panthor_group *group_from_handle(struct panthor_group_pool *pool, - u32 group_handle) + unsigned long group_handle) { struct panthor_group *group; xa_lock(&pool->xa); - group = group_get(xa_load(&pool->xa, group_handle)); + group = group_get(xa_find(&pool->xa, &group_handle, group_handle, GROUP_REGISTERED)); xa_unlock(&pool->xa); return group; @@ -3861,7 +3872,7 @@ panthor_fdinfo_gather_group_mem_info(struct panthor_file *pfile, return; xa_lock(&gpool->xa); - xa_for_each(&gpool->xa, i, group) { + xa_for_each_marked(&gpool->xa, i, group, GROUP_REGISTERED) { stats->resident += group->fdinfo.kbo_sizes; if (group->csg_id >= 0) stats->active += group->fdinfo.kbo_sizes; diff --git a/drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c b/drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c index 9413b76d0bfc..4ef2e3c129ed 100644 --- a/drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c @@ -492,9 +492,9 @@ static void rcar_mipi_dsi_set_display_timing(struct rcar_mipi_dsi *dsi, /* Configuration for Video Parameters, input is always RGB888 */ vprmset0r = TXVMVPRMSET0R_BPP_24; - if (mode->flags & DRM_MODE_FLAG_NVSYNC) + if (!(mode->flags & DRM_MODE_FLAG_PVSYNC)) vprmset0r |= TXVMVPRMSET0R_VSPOL_LOW; - if (mode->flags & DRM_MODE_FLAG_NHSYNC) + if (!(mode->flags & DRM_MODE_FLAG_PHSYNC)) vprmset0r |= TXVMVPRMSET0R_HSPOL_LOW; vprmset1r = TXVMVPRMSET1R_VACTIVE(mode->vdisplay) diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c index 5718d9d83a49..52c95131af5a 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c @@ -586,7 +586,7 @@ out: drm_modeset_unlock(&crtc->mutex); } -static void tilcdc_crtc_destroy(struct drm_crtc *crtc) +void tilcdc_crtc_destroy(struct drm_crtc *crtc) { struct tilcdc_drm_private *priv = crtc->dev->dev_private; diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 7caec4d38ddf..3dcbec312bac 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -172,8 +172,7 @@ static void tilcdc_fini(struct drm_device *dev) if (priv->crtc) tilcdc_crtc_shutdown(priv->crtc); - if (priv->is_registered) - drm_dev_unregister(dev); + drm_dev_unregister(dev); drm_kms_helper_poll_fini(dev); drm_atomic_helper_shutdown(dev); @@ -220,21 +219,21 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev) priv->wq = alloc_ordered_workqueue("tilcdc", 0); if (!priv->wq) { ret = -ENOMEM; - goto init_failed; + goto put_drm; } priv->mmio = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->mmio)) { dev_err(dev, "failed to request / ioremap\n"); ret = PTR_ERR(priv->mmio); - goto init_failed; + goto free_wq; } priv->clk = clk_get(dev, "fck"); if (IS_ERR(priv->clk)) { dev_err(dev, "failed to get functional clock\n"); ret = -ENODEV; - goto init_failed; + goto free_wq; } pm_runtime_enable(dev); @@ -313,7 +312,7 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev) ret = tilcdc_crtc_create(ddev); if (ret < 0) { dev_err(dev, "failed to create crtc\n"); - goto init_failed; + goto disable_pm; } modeset_init(ddev); @@ -324,46 +323,46 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev) if (ret) { dev_err(dev, "failed to register cpufreq notifier\n"); priv->freq_transition.notifier_call = NULL; - goto init_failed; + goto destroy_crtc; } #endif if (priv->is_componentized) { ret = component_bind_all(dev, ddev); if (ret < 0) - goto init_failed; + goto unregister_cpufreq_notif; ret = tilcdc_add_component_encoder(ddev); if (ret < 0) - goto init_failed; + goto unbind_component; } else { ret = tilcdc_attach_external_device(ddev); if (ret) - goto init_failed; + goto unregister_cpufreq_notif; } if (!priv->external_connector && ((priv->num_encoders == 0) || (priv->num_connectors == 0))) { dev_err(dev, "no encoders/connectors found\n"); ret = -EPROBE_DEFER; - goto init_failed; + goto unbind_component; } ret = drm_vblank_init(ddev, 1); if (ret < 0) { dev_err(dev, "failed to initialize vblank\n"); - goto init_failed; + goto unbind_component; } ret = platform_get_irq(pdev, 0); if (ret < 0) - goto init_failed; + goto unbind_component; priv->irq = ret; ret = tilcdc_irq_install(ddev, priv->irq); if (ret < 0) { dev_err(dev, "failed to install IRQ handler\n"); - goto init_failed; + goto unbind_component; } drm_mode_config_reset(ddev); @@ -372,16 +371,34 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev) ret = drm_dev_register(ddev, 0); if (ret) - goto init_failed; - priv->is_registered = true; + goto stop_poll; drm_client_setup_with_color_mode(ddev, bpp); return 0; -init_failed: - tilcdc_fini(ddev); +stop_poll: + drm_kms_helper_poll_fini(ddev); + tilcdc_irq_uninstall(ddev); +unbind_component: + if (priv->is_componentized) + component_unbind_all(dev, ddev); +unregister_cpufreq_notif: +#ifdef CONFIG_CPU_FREQ + cpufreq_unregister_notifier(&priv->freq_transition, + CPUFREQ_TRANSITION_NOTIFIER); +destroy_crtc: +#endif + tilcdc_crtc_destroy(priv->crtc); +disable_pm: + pm_runtime_disable(dev); + clk_put(priv->clk); +free_wq: + destroy_workqueue(priv->wq); +put_drm: platform_set_drvdata(pdev, NULL); + ddev->dev_private = NULL; + drm_dev_put(ddev); return ret; } diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h index b818448c83f6..58b276f82a66 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h @@ -82,7 +82,6 @@ struct tilcdc_drm_private { struct drm_encoder *external_encoder; struct drm_connector *external_connector; - bool is_registered; bool is_componentized; bool irq_enabled; }; @@ -164,6 +163,7 @@ void tilcdc_crtc_set_panel_info(struct drm_crtc *crtc, void tilcdc_crtc_set_simulate_vesa_sync(struct drm_crtc *crtc, bool simulate_vesa_sync); void tilcdc_crtc_shutdown(struct drm_crtc *crtc); +void tilcdc_crtc_destroy(struct drm_crtc *crtc); int tilcdc_crtc_update_fb(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event); diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c index b47020fca199..e6abc7b40b18 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_vm.c +++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c @@ -434,6 +434,11 @@ int ttm_bo_access(struct ttm_buffer_object *bo, unsigned long offset, if (ret) return ret; + if (!bo->resource) { + ret = -ENODATA; + goto unlock; + } + switch (bo->resource->mem_type) { case TTM_PL_SYSTEM: fallthrough; @@ -448,6 +453,7 @@ int ttm_bo_access(struct ttm_buffer_object *bo, unsigned long offset, ret = -EIO; } +unlock: ttm_bo_unreserve(bo); return ret; diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index f88f7e19203a..7f606c871648 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c @@ -1742,11 +1742,10 @@ EXPORT_SYMBOL_GPL(i3c_master_do_daa); struct i3c_dma *i3c_master_dma_map_single(struct device *dev, void *buf, size_t len, bool force_bounce, enum dma_data_direction dir) { - struct i3c_dma *dma_xfer __free(kfree) = NULL; void *bounce __free(kfree) = NULL; void *dma_buf = buf; - dma_xfer = kzalloc(sizeof(*dma_xfer), GFP_KERNEL); + struct i3c_dma *dma_xfer __free(kfree) = kzalloc(sizeof(*dma_xfer), GFP_KERNEL); if (!dma_xfer) return NULL; @@ -2819,14 +2818,10 @@ EXPORT_SYMBOL_GPL(i3c_generic_ibi_recycle_slot); static int i3c_master_check_ops(const struct i3c_master_controller_ops *ops) { - if (!ops || !ops->bus_init || + if (!ops || !ops->bus_init || !ops->i3c_xfers || !ops->send_ccc_cmd || !ops->do_daa || !ops->i2c_xfers) return -EINVAL; - /* Must provide one of priv_xfers (SDR only) or i3c_xfers (all modes) */ - if (!ops->priv_xfers && !ops->i3c_xfers) - return -EINVAL; - if (ops->request_ibi && (!ops->enable_ibi || !ops->disable_ibi || !ops->free_ibi || !ops->recycle_ibi_slot)) @@ -3031,13 +3026,7 @@ int i3c_dev_do_xfers_locked(struct i3c_dev_desc *dev, struct i3c_xfer *xfers, if (mode != I3C_SDR && !(master->this->info.hdr_cap & BIT(mode))) return -EOPNOTSUPP; - if (master->ops->i3c_xfers) - return master->ops->i3c_xfers(dev, xfers, nxfers, mode); - - if (mode != I3C_SDR) - return -EINVAL; - - return master->ops->priv_xfers(dev, xfers, nxfers); + return master->ops->i3c_xfers(dev, xfers, nxfers, mode); } int i3c_dev_disable_ibi_locked(struct i3c_dev_desc *dev) diff --git a/drivers/i3c/master/adi-i3c-master.c b/drivers/i3c/master/adi-i3c-master.c index 82ac0b3d057a..6380a38e6d29 100644 --- a/drivers/i3c/master/adi-i3c-master.c +++ b/drivers/i3c/master/adi-i3c-master.c @@ -332,10 +332,9 @@ static int adi_i3c_master_send_ccc_cmd(struct i3c_master_controller *m, struct i3c_ccc_cmd *cmd) { struct adi_i3c_master *master = to_adi_i3c_master(m); - struct adi_i3c_xfer *xfer __free(kfree) = NULL; struct adi_i3c_cmd *ccmd; - xfer = adi_i3c_master_alloc_xfer(master, 1); + struct adi_i3c_xfer *xfer __free(kfree) = adi_i3c_master_alloc_xfer(master, 1); if (!xfer) return -ENOMEM; @@ -365,19 +364,18 @@ static int adi_i3c_master_send_ccc_cmd(struct i3c_master_controller *m, return 0; } -static int adi_i3c_master_priv_xfers(struct i3c_dev_desc *dev, - struct i3c_priv_xfer *xfers, - int nxfers) +static int adi_i3c_master_i3c_xfers(struct i3c_dev_desc *dev, + struct i3c_xfer *xfers, + int nxfers, enum i3c_xfer_mode mode) { struct i3c_master_controller *m = i3c_dev_get_master(dev); struct adi_i3c_master *master = to_adi_i3c_master(m); - struct adi_i3c_xfer *xfer __free(kfree) = NULL; int i, ret; if (!nxfers) return 0; - xfer = adi_i3c_master_alloc_xfer(master, nxfers); + struct adi_i3c_xfer *xfer __free(kfree) = adi_i3c_master_alloc_xfer(master, nxfers); if (!xfer) return -ENOMEM; @@ -777,7 +775,6 @@ static int adi_i3c_master_i2c_xfers(struct i2c_dev_desc *dev, { struct i3c_master_controller *m = i2c_dev_get_master(dev); struct adi_i3c_master *master = to_adi_i3c_master(m); - struct adi_i3c_xfer *xfer __free(kfree) = NULL; int i; if (!nxfers) @@ -786,7 +783,8 @@ static int adi_i3c_master_i2c_xfers(struct i2c_dev_desc *dev, if (xfers[i].flags & I2C_M_TEN) return -EOPNOTSUPP; } - xfer = adi_i3c_master_alloc_xfer(master, nxfers); + + struct adi_i3c_xfer *xfer __free(kfree) = adi_i3c_master_alloc_xfer(master, nxfers); if (!xfer) return -ENOMEM; @@ -919,7 +917,7 @@ static const struct i3c_master_controller_ops adi_i3c_master_ops = { .do_daa = adi_i3c_master_do_daa, .supports_ccc_cmd = adi_i3c_master_supports_ccc_cmd, .send_ccc_cmd = adi_i3c_master_send_ccc_cmd, - .priv_xfers = adi_i3c_master_priv_xfers, + .i3c_xfers = adi_i3c_master_i3c_xfers, .i2c_xfers = adi_i3c_master_i2c_xfers, .request_ibi = adi_i3c_master_request_ibi, .enable_ibi = adi_i3c_master_enable_ibi, diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c index 276592a8222e..889e2ed5bc83 100644 --- a/drivers/i3c/master/dw-i3c-master.c +++ b/drivers/i3c/master/dw-i3c-master.c @@ -902,9 +902,9 @@ rpm_out: return ret; } -static int dw_i3c_master_priv_xfers(struct i3c_dev_desc *dev, - struct i3c_priv_xfer *i3c_xfers, - int i3c_nxfers) +static int dw_i3c_master_i3c_xfers(struct i3c_dev_desc *dev, + struct i3c_xfer *i3c_xfers, + int i3c_nxfers, enum i3c_xfer_mode mode) { struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); struct i3c_master_controller *m = i3c_dev_get_master(dev); @@ -1498,7 +1498,7 @@ static const struct i3c_master_controller_ops dw_mipi_i3c_ops = { .do_daa = dw_i3c_master_daa, .supports_ccc_cmd = dw_i3c_master_supports_ccc_cmd, .send_ccc_cmd = dw_i3c_master_send_ccc_cmd, - .priv_xfers = dw_i3c_master_priv_xfers, + .i3c_xfers = dw_i3c_master_i3c_xfers, .attach_i2c_dev = dw_i3c_master_attach_i2c_dev, .detach_i2c_dev = dw_i3c_master_detach_i2c_dev, .i2c_xfers = dw_i3c_master_i2c_xfers, diff --git a/drivers/i3c/master/i3c-master-cdns.c b/drivers/i3c/master/i3c-master-cdns.c index 97b151564d3d..8eb76b8ca2b0 100644 --- a/drivers/i3c/master/i3c-master-cdns.c +++ b/drivers/i3c/master/i3c-master-cdns.c @@ -720,9 +720,9 @@ static int cdns_i3c_master_send_ccc_cmd(struct i3c_master_controller *m, return ret; } -static int cdns_i3c_master_priv_xfers(struct i3c_dev_desc *dev, - struct i3c_priv_xfer *xfers, - int nxfers) +static int cdns_i3c_master_i3c_xfers(struct i3c_dev_desc *dev, + struct i3c_xfer *xfers, + int nxfers, enum i3c_xfer_mode mode) { struct i3c_master_controller *m = i3c_dev_get_master(dev); struct cdns_i3c_master *master = to_cdns_i3c_master(m); @@ -1519,7 +1519,7 @@ static const struct i3c_master_controller_ops cdns_i3c_master_ops = { .detach_i2c_dev = cdns_i3c_master_detach_i2c_dev, .supports_ccc_cmd = cdns_i3c_master_supports_ccc_cmd, .send_ccc_cmd = cdns_i3c_master_send_ccc_cmd, - .priv_xfers = cdns_i3c_master_priv_xfers, + .i3c_xfers = cdns_i3c_master_i3c_xfers, .i2c_xfers = cdns_i3c_master_i2c_xfers, .enable_ibi = cdns_i3c_master_enable_ibi, .disable_ibi = cdns_i3c_master_disable_ibi, diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c index 47e42cb4dbe7..607d77ab0e54 100644 --- a/drivers/i3c/master/mipi-i3c-hci/core.c +++ b/drivers/i3c/master/mipi-i3c-hci/core.c @@ -266,9 +266,9 @@ static int i3c_hci_daa(struct i3c_master_controller *m) return hci->cmd->perform_daa(hci); } -static int i3c_hci_priv_xfers(struct i3c_dev_desc *dev, - struct i3c_priv_xfer *i3c_xfers, - int nxfers) +static int i3c_hci_i3c_xfers(struct i3c_dev_desc *dev, + struct i3c_xfer *i3c_xfers, int nxfers, + enum i3c_xfer_mode mode) { struct i3c_master_controller *m = i3c_dev_get_master(dev); struct i3c_hci *hci = to_i3c_hci(m); @@ -515,7 +515,7 @@ static const struct i3c_master_controller_ops i3c_hci_ops = { .bus_cleanup = i3c_hci_bus_cleanup, .do_daa = i3c_hci_daa, .send_ccc_cmd = i3c_hci_send_ccc_cmd, - .priv_xfers = i3c_hci_priv_xfers, + .i3c_xfers = i3c_hci_i3c_xfers, .i2c_xfers = i3c_hci_i2c_xfers, .attach_i3c_dev = i3c_hci_attach_i3c_dev, .reattach_i3c_dev = i3c_hci_reattach_i3c_dev, diff --git a/drivers/i3c/master/renesas-i3c.c b/drivers/i3c/master/renesas-i3c.c index 275f7b924288..426a418f29b6 100644 --- a/drivers/i3c/master/renesas-i3c.c +++ b/drivers/i3c/master/renesas-i3c.c @@ -794,8 +794,8 @@ static int renesas_i3c_send_ccc_cmd(struct i3c_master_controller *m, return ret; } -static int renesas_i3c_priv_xfers(struct i3c_dev_desc *dev, struct i3c_priv_xfer *i3c_xfers, - int i3c_nxfers) +static int renesas_i3c_i3c_xfers(struct i3c_dev_desc *dev, struct i3c_xfer *i3c_xfers, + int i3c_nxfers, enum i3c_xfer_mode mode) { struct i3c_master_controller *m = i3c_dev_get_master(dev); struct renesas_i3c *i3c = to_renesas_i3c(m); @@ -1282,7 +1282,7 @@ static const struct i3c_master_controller_ops renesas_i3c_ops = { .do_daa = renesas_i3c_daa, .supports_ccc_cmd = renesas_i3c_supports_ccc_cmd, .send_ccc_cmd = renesas_i3c_send_ccc_cmd, - .priv_xfers = renesas_i3c_priv_xfers, + .i3c_xfers = renesas_i3c_i3c_xfers, .attach_i2c_dev = renesas_i3c_attach_i2c_dev, .detach_i2c_dev = renesas_i3c_detach_i2c_dev, .i2c_xfers = renesas_i3c_i2c_xfers, diff --git a/drivers/irqchip/irq-loongarch-avec.c b/drivers/irqchip/irq-loongarch-avec.c index bf52dc8345f5..ba556c008cf3 100644 --- a/drivers/irqchip/irq-loongarch-avec.c +++ b/drivers/irqchip/irq-loongarch-avec.c @@ -209,8 +209,9 @@ static void avecintc_compose_msi_msg(struct irq_data *d, struct msi_msg *msg) struct avecintc_data *adata = irq_data_get_irq_chip_data(d); msg->address_hi = 0x0; - msg->address_lo = (loongarch_avec.msi_base_addr | (adata->vec & 0xff) << 4) - | ((cpu_logical_map(adata->cpu & 0xffff)) << 12); + msg->address_lo = (loongarch_avec.msi_base_addr | + (adata->vec & AVEC_IRQ_MASK) << AVEC_IRQ_SHIFT) | + ((cpu_logical_map(adata->cpu & AVEC_CPU_MASK)) << AVEC_CPU_SHIFT); msg->data = 0x0; } diff --git a/drivers/irqchip/irq-mchp-eic.c b/drivers/irqchip/irq-mchp-eic.c index 2474fa467a05..31093a8ab67c 100644 --- a/drivers/irqchip/irq-mchp-eic.c +++ b/drivers/irqchip/irq-mchp-eic.c @@ -170,7 +170,7 @@ static int mchp_eic_domain_alloc(struct irq_domain *domain, unsigned int virq, ret = irq_domain_translate_twocell(domain, fwspec, &hwirq, &type); if (ret || hwirq >= MCHP_EIC_NIRQ) - return ret; + return ret ?: -EINVAL; switch (type) { case IRQ_TYPE_EDGE_RISING: diff --git a/drivers/of/property.c b/drivers/of/property.c index c1feb631e383..4e3524227720 100644 --- a/drivers/of/property.c +++ b/drivers/of/property.c @@ -148,6 +148,39 @@ static void *of_find_property_value_of_size(const struct device_node *np, } /** + * of_property_read_u8_index - Find and read a u8 from a multi-value property. + * + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * @index: index of the u8 in the list of values + * @out_value: pointer to return value, modified only if no error. + * + * Search for a property in a device node and read nth 8-bit value from + * it. + * + * Return: 0 on success, -EINVAL if the property does not exist, + * -ENODATA if property does not have a value, and -EOVERFLOW if the + * property data isn't large enough. + * + * The out_value is modified only if a valid u8 value can be decoded. + */ +int of_property_read_u8_index(const struct device_node *np, + const char *propname, + u32 index, u8 *out_value) +{ + const u8 *val = of_find_property_value_of_size(np, propname, + ((index + 1) * sizeof(*out_value)), + 0, NULL); + + if (IS_ERR(val)) + return PTR_ERR(val); + + *out_value = val[index]; + return 0; +} +EXPORT_SYMBOL_GPL(of_property_read_u8_index); + +/** * of_property_read_u16_index - Find and read a u16 from a multi-value property. * * @np: device node from which the property value is to be read. diff --git a/drivers/pci/controller/pcie-rzg3s-host.c b/drivers/pci/controller/pcie-rzg3s-host.c index 667e6d629474..83ec66a70823 100644 --- a/drivers/pci/controller/pcie-rzg3s-host.c +++ b/drivers/pci/controller/pcie-rzg3s-host.c @@ -479,7 +479,7 @@ static void rzg3s_pcie_intx_irq_handler(struct irq_desc *desc) static irqreturn_t rzg3s_pcie_msi_irq(int irq, void *data) { u8 regs = RZG3S_PCI_MSI_INT_NR / RZG3S_PCI_MSI_INT_PER_REG; - DECLARE_BITMAP(bitmap, RZG3S_PCI_MSI_INT_NR); + DECLARE_BITMAP(bitmap, RZG3S_PCI_MSI_INT_NR) = {0}; struct rzg3s_pcie_host *host = data; struct rzg3s_pcie_msi *msi = &host->msi; unsigned long bit; diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index bf2d101f67a1..6f3147518376 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -760,7 +760,9 @@ config PWM_TEGRA config PWM_TH1520 tristate "TH1520 PWM support" + depends on ARCH_THEAD || COMPILE_TEST depends on RUST + depends on HAS_IOMEM && COMMON_CLK select RUST_PWM_ABSTRACTIONS help This option enables the driver for the PWM controller found on the diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 2933c41c77c8..50dc779f7f98 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -409,13 +409,22 @@ config RTC_DRV_MAX77686 config RTC_DRV_SPACEMIT_P1 tristate "SpacemiT P1 RTC" depends on ARCH_SPACEMIT || COMPILE_TEST - select MFD_SPACEMIT_P1 - default ARCH_SPACEMIT + depends on MFD_SPACEMIT_P1 + default MFD_SPACEMIT_P1 help Enable support for the RTC function in the SpacemiT P1 PMIC. This driver can also be built as a module, which will be called "spacemit-p1-rtc". +config RTC_DRV_NVIDIA_VRS10 + tristate "NVIDIA VRS10 RTC device" + help + If you say yes here you will get support for the battery backed RTC device + of NVIDIA VRS (Voltage Regulator Specification). The RTC is connected via + I2C interface and supports alarm functionality. + This driver can also be built as a module. If so, the module will be called + rtc-nvidia-vrs10. + config RTC_DRV_NCT3018Y tristate "Nuvoton NCT3018Y" depends on OF @@ -1063,6 +1072,21 @@ config RTC_DRV_ALPHA Direct support for the real-time clock found on every Alpha system, specifically MC146818 compatibles. If in doubt, say Y. +config RTC_DRV_ATCRTC100 + tristate "Andes ATCRTC100" + depends on ARCH_ANDES || COMPILE_TEST + select REGMAP_MMIO + help + If you say yes here you will get support for the Andes ATCRTC100 + RTC driver. + + This driver provides support for the Andes ATCRTC100 real-time clock + device. It allows setting and retrieving the time and date, as well + as setting alarms. + + To compile this driver as a module, choose M here: the module will + be called rtc-atcrtc100. + config RTC_DRV_DS1216 tristate "Dallas DS1216" depends on SNI_RM @@ -1749,7 +1773,7 @@ config RTC_DRV_MC13XXX tristate "Freescale MC13xxx RTC" help This enables support for the RTCs found on Freescale's PMICs - MC13783 and MC13892. + MC13783, MC13892 and MC34708. config RTC_DRV_MPC5121 tristate "Freescale MPC5121 built-in RTC" @@ -2074,6 +2098,17 @@ config RTC_DRV_WILCO_EC This can also be built as a module. If so, the module will be named "rtc_wilco_ec". +config RTC_DRV_MACSMC + tristate "Apple Mac System Management Controller RTC" + depends on MFD_MACSMC + help + If you say yes here you get support for RTC functions + inside Apple SPMI PMUs accessed through the SoC's + System Management Controller + + To compile this driver as a module, choose M here: the + module will be called rtc-macsmc. + config RTC_DRV_MSC313 tristate "MStar MSC313 RTC" depends on ARCH_MSTARV7 || COMPILE_TEST diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 8221bda6e6dc..6cf7e066314e 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_RTC_DRV_ASM9260) += rtc-asm9260.o obj-$(CONFIG_RTC_DRV_ASPEED) += rtc-aspeed.o obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o +obj-$(CONFIG_RTC_DRV_ATCRTC100) += rtc-atcrtc100.o obj-$(CONFIG_RTC_DRV_AU1XXX) += rtc-au1xxx.o obj-$(CONFIG_RTC_DRV_BBNSM) += rtc-nxp-bbnsm.o obj-$(CONFIG_RTC_DRV_BD70528) += rtc-bd70528.o @@ -93,6 +94,7 @@ obj-$(CONFIG_RTC_DRV_M48T35) += rtc-m48t35.o obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o obj-$(CONFIG_RTC_DRV_MA35D1) += rtc-ma35d1.o +obj-$(CONFIG_RTC_DRV_MACSMC) += rtc-macsmc.o obj-$(CONFIG_RTC_DRV_MAX31335) += rtc-max31335.o obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o @@ -121,6 +123,7 @@ obj-$(CONFIG_RTC_DRV_GAMECUBE) += rtc-gamecube.o obj-$(CONFIG_RTC_DRV_NCT3018Y) += rtc-nct3018y.o obj-$(CONFIG_RTC_DRV_NCT6694) += rtc-nct6694.o obj-$(CONFIG_RTC_DRV_NTXEC) += rtc-ntxec.o +obj-$(CONFIG_RTC_DRV_NVIDIA_VRS10)+= rtc-nvidia-vrs10.o obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o obj-$(CONFIG_RTC_DRV_OPAL) += rtc-opal.o obj-$(CONFIG_RTC_DRV_OPTEE) += rtc-optee.o diff --git a/drivers/rtc/rtc-amlogic-a4.c b/drivers/rtc/rtc-amlogic-a4.c index 1928b29c1045..123fb372fc9f 100644 --- a/drivers/rtc/rtc-amlogic-a4.c +++ b/drivers/rtc/rtc-amlogic-a4.c @@ -361,39 +361,26 @@ static int aml_rtc_probe(struct platform_device *pdev) "failed to get_enable rtc sys clk\n"); aml_rtc_init(rtc); - device_init_wakeup(dev, true); + devm_device_init_wakeup(dev); platform_set_drvdata(pdev, rtc); rtc->rtc_dev = devm_rtc_allocate_device(dev); - if (IS_ERR(rtc->rtc_dev)) { - ret = PTR_ERR(rtc->rtc_dev); - goto err_clk; - } + if (IS_ERR(rtc->rtc_dev)) + return PTR_ERR(rtc->rtc_dev); ret = devm_request_irq(dev, rtc->irq, aml_rtc_handler, IRQF_ONESHOT, "aml-rtc alarm", rtc); if (ret) { dev_err_probe(dev, ret, "IRQ%d request failed, ret = %d\n", rtc->irq, ret); - goto err_clk; + return ret; } rtc->rtc_dev->ops = &aml_rtc_ops; rtc->rtc_dev->range_min = 0; rtc->rtc_dev->range_max = U32_MAX; - ret = devm_rtc_register_device(rtc->rtc_dev); - if (ret) { - dev_err_probe(&pdev->dev, ret, "Failed to register RTC device: %d\n", ret); - goto err_clk; - } - - return 0; -err_clk: - clk_disable_unprepare(rtc->sys_clk); - device_init_wakeup(dev, false); - - return ret; + return devm_rtc_register_device(rtc->rtc_dev); } #ifdef CONFIG_PM_SLEEP @@ -421,14 +408,6 @@ static int aml_rtc_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(aml_rtc_pm_ops, aml_rtc_suspend, aml_rtc_resume); -static void aml_rtc_remove(struct platform_device *pdev) -{ - struct aml_rtc_data *rtc = dev_get_drvdata(&pdev->dev); - - clk_disable_unprepare(rtc->sys_clk); - device_init_wakeup(&pdev->dev, false); -} - static const struct aml_rtc_config a5_rtc_config = { }; @@ -451,7 +430,6 @@ MODULE_DEVICE_TABLE(of, aml_rtc_device_id); static struct platform_driver aml_rtc_driver = { .probe = aml_rtc_probe, - .remove = aml_rtc_remove, .driver = { .name = "aml-rtc", .pm = &aml_rtc_pm_ops, diff --git a/drivers/rtc/rtc-atcrtc100.c b/drivers/rtc/rtc-atcrtc100.c new file mode 100644 index 000000000000..9808fc2c5a49 --- /dev/null +++ b/drivers/rtc/rtc-atcrtc100.c @@ -0,0 +1,381 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Driver for Andes ATCRTC100 real time clock. + * + * Copyright (C) 2025 Andes Technology Corporation + */ + +#include <linux/bitfield.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/math64.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm_wakeirq.h> +#include <linux/regmap.h> +#include <linux/rtc.h> +#include <linux/workqueue.h> + +/* Register Offsets */ +#define RTC_ID 0x00 /* ID and Revision Register */ +#define RTC_RSV 0x04 /* Reserved Register */ +#define RTC_CNT 0x10 /* Counter Register */ +#define RTC_ALM 0x14 /* Alarm Register */ +#define RTC_CR 0x18 /* Control Register */ +#define RTC_STA 0x1C /* Status Register */ +#define RTC_TRIM 0x20 /* Digital Trimming Register */ + +/* RTC_ID Register */ +#define ID_MSK GENMASK(31, 8) +#define ID_ATCRTC100 0x030110 + +/* RTC_CNT and RTC_ALM Register Fields */ +#define SEC_MSK GENMASK(5, 0) +#define MIN_MSK GENMASK(11, 6) +#define HOUR_MSK GENMASK(16, 12) +#define DAY_MSK GENMASK(31, 17) +#define RTC_SEC_GET(x) FIELD_GET(SEC_MSK, x) +#define RTC_MIN_GET(x) FIELD_GET(MIN_MSK, x) +#define RTC_HOUR_GET(x) FIELD_GET(HOUR_MSK, x) +#define RTC_DAY_GET(x) FIELD_GET(DAY_MSK, x) +#define RTC_SEC_SET(x) FIELD_PREP(SEC_MSK, x) +#define RTC_MIN_SET(x) FIELD_PREP(MIN_MSK, x) +#define RTC_HOUR_SET(x) FIELD_PREP(HOUR_MSK, x) +#define RTC_DAY_SET(x) FIELD_PREP(DAY_MSK, x) + +/* RTC_CR Register Bits */ +#define RTC_EN BIT(0) /* RTC Enable */ +#define ALARM_WAKEUP BIT(1) /* Alarm Wakeup Enable */ +#define ALARM_INT BIT(2) /* Alarm Interrupt Enable */ +#define DAY_INT BIT(3) /* Day Interrupt Enable */ +#define HOUR_INT BIT(4) /* Hour Interrupt Enable */ +#define MIN_INT BIT(5) /* Minute Interrupt Enable */ +#define SEC_INT BIT(6) /* Second Periodic Interrupt Enable */ +#define HSEC_INT BIT(7) /* Half-Second Periodic Interrupt Enable */ + +/* RTC_STA Register Bits */ +#define WRITE_DONE BIT(16) /* Register write completion status */ + +/* Time conversion macro */ +#define ATCRTC_TIME_TO_SEC(D, H, M, S) \ + ((time64_t)(D) * 86400 + (H) * 3600 + (M) * 60 + (S)) + +/* Timeout for waiting for the write_done bit */ +#define ATCRTC_TIMEOUT_US 1000000 +#define ATCRTC_TIMEOUT_USLEEP_MIN 20 +#define ATCRTC_TIMEOUT_USLEEP_MAX 30 + +struct atcrtc_dev { + struct rtc_device *rtc_dev; + struct regmap *regmap; + struct work_struct rtc_work; + unsigned int alarm_irq; + bool alarm_en; +}; + +static const struct regmap_config atcrtc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = RTC_TRIM, + .cache_type = REGCACHE_NONE, +}; + +/** + * atcrtc_check_write_done - Wait for RTC registers to be synchronized. + * @rtc: Pointer to the atcrtc_dev structure. + * + * The WriteDone bit in the status register indicates the synchronization + * progress of RTC register updates. This bit is cleared to zero whenever + * any RTC control register (Counter, Alarm, Control, etc.) is written. + * It returns to one only after all previous updates have been fully + * synchronized to the RTC clock domain. This function polls the WriteDone + * bit with a timeout to ensure the device is ready for the next operation. + * + * Return: 0 on success, or -EBUSY on timeout. + */ +static int atcrtc_check_write_done(struct atcrtc_dev *rtc) +{ + unsigned int val; + + /* + * Using read_poll_timeout is more efficient than a manual loop + * with usleep_range. + */ + return regmap_read_poll_timeout(rtc->regmap, RTC_STA, val, + val & WRITE_DONE, + ATCRTC_TIMEOUT_USLEEP_MIN, + ATCRTC_TIMEOUT_US); +} + +static irqreturn_t atcrtc_alarm_isr(int irq, void *dev) +{ + struct atcrtc_dev *rtc = dev; + unsigned int status; + + regmap_read(rtc->regmap, RTC_STA, &status); + if (status & ALARM_INT) { + regmap_write(rtc->regmap, RTC_STA, ALARM_INT); + rtc->alarm_en = false; + schedule_work(&rtc->rtc_work); + rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF); + return IRQ_HANDLED; + } + return IRQ_NONE; +} + +static int atcrtc_alarm_irq_enable(struct device *dev, unsigned int enable) +{ + struct atcrtc_dev *rtc = dev_get_drvdata(dev); + unsigned int mask; + int ret; + + ret = atcrtc_check_write_done(rtc); + if (ret) + return ret; + + mask = ALARM_WAKEUP | ALARM_INT; + regmap_update_bits(rtc->regmap, RTC_CR, mask, enable ? mask : 0); + + return 0; +} + +static void atcrtc_alarm_clear(struct work_struct *work) +{ + struct atcrtc_dev *rtc = + container_of(work, struct atcrtc_dev, rtc_work); + int ret; + + rtc_lock(rtc->rtc_dev); + + if (!rtc->alarm_en) { + ret = atcrtc_check_write_done(rtc); + if (ret) + dev_info(&rtc->rtc_dev->dev, + "failed to sync before clearing alarm: %d\n", + ret); + else + regmap_update_bits(rtc->regmap, RTC_CR, + ALARM_WAKEUP | ALARM_INT, 0); + } + rtc_unlock(rtc->rtc_dev); +} + +static int atcrtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct atcrtc_dev *rtc = dev_get_drvdata(dev); + time64_t time; + unsigned int rtc_cnt; + + if (!regmap_test_bits(rtc->regmap, RTC_CR, RTC_EN)) + return -EIO; + + regmap_read(rtc->regmap, RTC_CNT, &rtc_cnt); + time = ATCRTC_TIME_TO_SEC(RTC_DAY_GET(rtc_cnt), + RTC_HOUR_GET(rtc_cnt), + RTC_MIN_GET(rtc_cnt), + RTC_SEC_GET(rtc_cnt)); + rtc_time64_to_tm(time, tm); + + return 0; +} + +static int atcrtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct atcrtc_dev *rtc = dev_get_drvdata(dev); + time64_t time; + unsigned int counter; + unsigned int day; + int ret; + + time = rtc_tm_to_time64(tm); + day = div_s64(time, 86400); + counter = RTC_DAY_SET(day) | + RTC_HOUR_SET(tm->tm_hour) | + RTC_MIN_SET(tm->tm_min) | + RTC_SEC_SET(tm->tm_sec); + ret = atcrtc_check_write_done(rtc); + if (ret) + return ret; + regmap_write(rtc->regmap, RTC_CNT, counter); + + ret = atcrtc_check_write_done(rtc); + if (ret) + return ret; + regmap_update_bits(rtc->regmap, RTC_CR, RTC_EN, RTC_EN); + + return 0; +} + +static int atcrtc_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) +{ + struct atcrtc_dev *rtc = dev_get_drvdata(dev); + struct rtc_time *tm = &wkalrm->time; + unsigned int rtc_alarm; + + wkalrm->enabled = regmap_test_bits(rtc->regmap, RTC_CR, ALARM_INT); + regmap_read(rtc->regmap, RTC_ALM, &rtc_alarm); + tm->tm_hour = RTC_HOUR_GET(rtc_alarm); + tm->tm_min = RTC_MIN_GET(rtc_alarm); + tm->tm_sec = RTC_SEC_GET(rtc_alarm); + + /* The RTC alarm does not support day/month/year fields */ + tm->tm_mday = -1; + tm->tm_mon = -1; + tm->tm_year = -1; + + return 0; +} + +static int atcrtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) +{ + struct atcrtc_dev *rtc = dev_get_drvdata(dev); + struct rtc_time *tm = &wkalrm->time; + unsigned int rtc_alarm; + int ret; + + /* Disable alarm first before setting a new one */ + ret = atcrtc_alarm_irq_enable(dev, 0); + if (ret) + return ret; + + rtc->alarm_en = false; + + rtc_alarm = RTC_SEC_SET(tm->tm_sec) | + RTC_MIN_SET(tm->tm_min) | + RTC_HOUR_SET(tm->tm_hour); + + ret = atcrtc_check_write_done(rtc); + if (ret) + return ret; + + regmap_write(rtc->regmap, RTC_ALM, rtc_alarm); + + rtc->alarm_en = wkalrm->enabled; + ret = atcrtc_alarm_irq_enable(dev, wkalrm->enabled); + + return ret; +} + +static const struct rtc_class_ops rtc_ops = { + .read_time = atcrtc_read_time, + .set_time = atcrtc_set_time, + .read_alarm = atcrtc_read_alarm, + .set_alarm = atcrtc_set_alarm, + .alarm_irq_enable = atcrtc_alarm_irq_enable, +}; + +static int atcrtc_probe(struct platform_device *pdev) +{ + struct atcrtc_dev *atcrtc_dev; + void __iomem *reg_base; + unsigned int rtc_id; + int ret; + + atcrtc_dev = devm_kzalloc(&pdev->dev, sizeof(*atcrtc_dev), GFP_KERNEL); + if (!atcrtc_dev) + return -ENOMEM; + platform_set_drvdata(pdev, atcrtc_dev); + + reg_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(reg_base)) + return dev_err_probe(&pdev->dev, PTR_ERR(reg_base), + "Failed to map I/O space\n"); + + atcrtc_dev->regmap = devm_regmap_init_mmio(&pdev->dev, + reg_base, + &atcrtc_regmap_config); + if (IS_ERR(atcrtc_dev->regmap)) + return dev_err_probe(&pdev->dev, PTR_ERR(atcrtc_dev->regmap), + "Failed to initialize regmap\n"); + + regmap_read(atcrtc_dev->regmap, RTC_ID, &rtc_id); + if (FIELD_GET(ID_MSK, rtc_id) != ID_ATCRTC100) + return dev_err_probe(&pdev->dev, -ENODEV, + "Failed to initialize RTC: unsupported hardware ID 0x%x\n", + rtc_id); + + ret = platform_get_irq(pdev, 1); + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, + "Failed to get IRQ for alarm\n"); + atcrtc_dev->alarm_irq = ret; + + ret = devm_request_irq(&pdev->dev, + atcrtc_dev->alarm_irq, + atcrtc_alarm_isr, + 0, + "atcrtc_alarm", + atcrtc_dev); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Failed to request IRQ %d for alarm\n", + atcrtc_dev->alarm_irq); + + atcrtc_dev->rtc_dev = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(atcrtc_dev->rtc_dev)) + return dev_err_probe(&pdev->dev, PTR_ERR(atcrtc_dev->rtc_dev), + "Failed to allocate RTC device\n"); + + set_bit(RTC_FEATURE_ALARM, atcrtc_dev->rtc_dev->features); + ret = device_init_wakeup(&pdev->dev, true); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Failed to initialize wake capability\n"); + + ret = dev_pm_set_wake_irq(&pdev->dev, atcrtc_dev->alarm_irq); + if (ret) { + device_init_wakeup(&pdev->dev, false); + return dev_err_probe(&pdev->dev, ret, + "Failed to set wake IRQ\n"); + } + + atcrtc_dev->rtc_dev->ops = &rtc_ops; + + INIT_WORK(&atcrtc_dev->rtc_work, atcrtc_alarm_clear); + return devm_rtc_register_device(atcrtc_dev->rtc_dev); +} + +static int atcrtc_resume(struct device *dev) +{ + struct atcrtc_dev *rtc = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + disable_irq_wake(rtc->alarm_irq); + + return 0; +} + +static int atcrtc_suspend(struct device *dev) +{ + struct atcrtc_dev *rtc = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + enable_irq_wake(rtc->alarm_irq); + + return 0; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(atcrtc_pm_ops, atcrtc_suspend, atcrtc_resume); + +static const struct of_device_id atcrtc_dt_match[] = { + { .compatible = "andestech,atcrtc100" }, + { }, +}; +MODULE_DEVICE_TABLE(of, atcrtc_dt_match); + +static struct platform_driver atcrtc_platform_driver = { + .driver = { + .name = "atcrtc100", + .of_match_table = atcrtc_dt_match, + .pm = pm_sleep_ptr(&atcrtc_pm_ops), + }, + .probe = atcrtc_probe, +}; + +module_platform_driver(atcrtc_platform_driver); + +MODULE_AUTHOR("CL Wang <cl634@andestech.com>"); +MODULE_DESCRIPTION("Andes ATCRTC100 driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-ds1685.c b/drivers/rtc/rtc-ds1685.c index 97423f1d0361..5fc8e36b1abf 100644 --- a/drivers/rtc/rtc-ds1685.c +++ b/drivers/rtc/rtc-ds1685.c @@ -1268,9 +1268,6 @@ ds1685_rtc_probe(struct platform_device *pdev) rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_2000; rtc_dev->range_max = RTC_TIMESTAMP_END_2099; - /* Maximum periodic rate is 8192Hz (0.122070ms). */ - rtc_dev->max_user_freq = RTC_MAX_USER_FREQ; - /* See if the platform doesn't support UIE. */ if (pdata->uie_unsupported) clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc_dev->features); diff --git a/drivers/rtc/rtc-gamecube.c b/drivers/rtc/rtc-gamecube.c index c828bc8e05b9..045d5d45ab4b 100644 --- a/drivers/rtc/rtc-gamecube.c +++ b/drivers/rtc/rtc-gamecube.c @@ -242,6 +242,10 @@ static int gamecube_rtc_read_offset_from_sram(struct priv *d) } hw_srnprot = ioremap(res.start, resource_size(&res)); + if (!hw_srnprot) { + pr_err("failed to ioremap hw_srnprot\n"); + return -ENOMEM; + } old = ioread32be(hw_srnprot); /* TODO: figure out why we use this magic constant. I obtained it by diff --git a/drivers/rtc/rtc-isl12026.c b/drivers/rtc/rtc-isl12026.c index 2aabb9151d4c..45a2c9f676c5 100644 --- a/drivers/rtc/rtc-isl12026.c +++ b/drivers/rtc/rtc-isl12026.c @@ -484,6 +484,12 @@ static const struct of_device_id isl12026_dt_match[] = { }; MODULE_DEVICE_TABLE(of, isl12026_dt_match); +static const struct i2c_device_id isl12026_id[] = { + { "isl12026" }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, isl12026_id); + static struct i2c_driver isl12026_driver = { .driver = { .name = "rtc-isl12026", @@ -491,6 +497,7 @@ static struct i2c_driver isl12026_driver = { }, .probe = isl12026_probe, .remove = isl12026_remove, + .id_table = isl12026_id, }; module_i2c_driver(isl12026_driver); diff --git a/drivers/rtc/rtc-macsmc.c b/drivers/rtc/rtc-macsmc.c new file mode 100644 index 000000000000..8fe883066956 --- /dev/null +++ b/drivers/rtc/rtc-macsmc.c @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Apple SMC RTC driver + * Copyright The Asahi Linux Contributors + */ + +#include <linux/bitops.h> +#include <linux/mfd/macsmc.h> +#include <linux/module.h> +#include <linux/nvmem-consumer.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/rtc.h> +#include <linux/slab.h> + +/* 48-bit RTC */ +#define RTC_BYTES 6 +#define RTC_BITS (8 * RTC_BYTES) + +/* 32768 Hz clock */ +#define RTC_SEC_SHIFT 15 + +struct macsmc_rtc { + struct device *dev; + struct apple_smc *smc; + struct rtc_device *rtc_dev; + struct nvmem_cell *rtc_offset; +}; + +static int macsmc_rtc_get_time(struct device *dev, struct rtc_time *tm) +{ + struct macsmc_rtc *rtc = dev_get_drvdata(dev); + u64 ctr = 0, off = 0; + time64_t now; + void *p_off; + size_t len; + int ret; + + ret = apple_smc_read(rtc->smc, SMC_KEY(CLKM), &ctr, RTC_BYTES); + if (ret < 0) + return ret; + if (ret != RTC_BYTES) + return -EIO; + + p_off = nvmem_cell_read(rtc->rtc_offset, &len); + if (IS_ERR(p_off)) + return PTR_ERR(p_off); + if (len < RTC_BYTES) { + kfree(p_off); + return -EIO; + } + + memcpy(&off, p_off, RTC_BYTES); + kfree(p_off); + + /* Sign extend from 48 to 64 bits, then arithmetic shift right 15 bits to get seconds */ + now = sign_extend64(ctr + off, RTC_BITS - 1) >> RTC_SEC_SHIFT; + rtc_time64_to_tm(now, tm); + + return ret; +} + +static int macsmc_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct macsmc_rtc *rtc = dev_get_drvdata(dev); + u64 ctr = 0, off = 0; + int ret; + + ret = apple_smc_read(rtc->smc, SMC_KEY(CLKM), &ctr, RTC_BYTES); + if (ret < 0) + return ret; + if (ret != RTC_BYTES) + return -EIO; + + /* This sets the offset such that the set second begins now */ + off = (rtc_tm_to_time64(tm) << RTC_SEC_SHIFT) - ctr; + return nvmem_cell_write(rtc->rtc_offset, &off, RTC_BYTES); +} + +static const struct rtc_class_ops macsmc_rtc_ops = { + .read_time = macsmc_rtc_get_time, + .set_time = macsmc_rtc_set_time, +}; + +static int macsmc_rtc_probe(struct platform_device *pdev) +{ + struct apple_smc *smc = dev_get_drvdata(pdev->dev.parent); + struct macsmc_rtc *rtc; + + /* + * MFD will probe this device even without a node in the device tree, + * thus bail out early if the SMC on the current machines does not + * support RTC and has no node in the device tree. + */ + if (!pdev->dev.of_node) + return -ENODEV; + + rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); + if (!rtc) + return -ENOMEM; + + rtc->dev = &pdev->dev; + rtc->smc = smc; + + rtc->rtc_offset = devm_nvmem_cell_get(&pdev->dev, "rtc_offset"); + if (IS_ERR(rtc->rtc_offset)) + return dev_err_probe(&pdev->dev, PTR_ERR(rtc->rtc_offset), + "Failed to get rtc_offset NVMEM cell\n"); + + rtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(rtc->rtc_dev)) + return PTR_ERR(rtc->rtc_dev); + + rtc->rtc_dev->ops = &macsmc_rtc_ops; + rtc->rtc_dev->range_min = S64_MIN >> (RTC_SEC_SHIFT + (64 - RTC_BITS)); + rtc->rtc_dev->range_max = S64_MAX >> (RTC_SEC_SHIFT + (64 - RTC_BITS)); + + platform_set_drvdata(pdev, rtc); + + return devm_rtc_register_device(rtc->rtc_dev); +} + +static const struct of_device_id macsmc_rtc_of_table[] = { + { .compatible = "apple,smc-rtc", }, + {} +}; +MODULE_DEVICE_TABLE(of, macsmc_rtc_of_table); + +static struct platform_driver macsmc_rtc_driver = { + .driver = { + .name = "macsmc-rtc", + .of_match_table = macsmc_rtc_of_table, + }, + .probe = macsmc_rtc_probe, +}; +module_platform_driver(macsmc_rtc_driver); + +MODULE_LICENSE("Dual MIT/GPL"); +MODULE_DESCRIPTION("Apple SMC RTC driver"); +MODULE_AUTHOR("Hector Martin <marcan@marcan.st>"); diff --git a/drivers/rtc/rtc-max31335.c b/drivers/rtc/rtc-max31335.c index dfb5bad3a369..23b7bf16b4cd 100644 --- a/drivers/rtc/rtc-max31335.c +++ b/drivers/rtc/rtc-max31335.c @@ -391,10 +391,8 @@ static int max31335_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) if (ret) return ret; - ret = regmap_update_bits(max31335->regmap, max31335->chip->int_status_reg, - MAX31335_STATUS1_A1F, 0); - - return 0; + return regmap_update_bits(max31335->regmap, max31335->chip->int_status_reg, + MAX31335_STATUS1_A1F, 0); } static int max31335_alarm_irq_enable(struct device *dev, unsigned int enabled) diff --git a/drivers/rtc/rtc-nvidia-vrs10.c b/drivers/rtc/rtc-nvidia-vrs10.c new file mode 100644 index 000000000000..b15796698558 --- /dev/null +++ b/drivers/rtc/rtc-nvidia-vrs10.c @@ -0,0 +1,542 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * NVIDIA Voltage Regulator Specification RTC + * + * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. + * All rights reserved. + */ + +#include <linux/bits.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/rtc.h> + +#define NVVRS_REG_VENDOR_ID 0x00 +#define NVVRS_REG_MODEL_REV 0x01 + +/* Interrupts registers */ +#define NVVRS_REG_INT_SRC1 0x10 +#define NVVRS_REG_INT_SRC2 0x11 +#define NVVRS_REG_INT_VENDOR 0x12 + +/* Control Registers */ +#define NVVRS_REG_CTL_1 0x28 +#define NVVRS_REG_CTL_2 0x29 + +/* RTC Registers */ +#define NVVRS_REG_RTC_T3 0x70 +#define NVVRS_REG_RTC_T2 0x71 +#define NVVRS_REG_RTC_T1 0x72 +#define NVVRS_REG_RTC_T0 0x73 +#define NVVRS_REG_RTC_A3 0x74 +#define NVVRS_REG_RTC_A2 0x75 +#define NVVRS_REG_RTC_A1 0x76 +#define NVVRS_REG_RTC_A0 0x77 + +/* Interrupt Mask */ +#define NVVRS_INT_SRC1_RSTIRQ_MASK BIT(0) +#define NVVRS_INT_SRC1_OSC_MASK BIT(1) +#define NVVRS_INT_SRC1_EN_MASK BIT(2) +#define NVVRS_INT_SRC1_RTC_MASK BIT(3) +#define NVVRS_INT_SRC1_PEC_MASK BIT(4) +#define NVVRS_INT_SRC1_WDT_MASK BIT(5) +#define NVVRS_INT_SRC1_EM_PD_MASK BIT(6) +#define NVVRS_INT_SRC1_INTERNAL_MASK BIT(7) +#define NVVRS_INT_SRC2_PBSP_MASK BIT(0) +#define NVVRS_INT_SRC2_ECC_DED_MASK BIT(1) +#define NVVRS_INT_SRC2_TSD_MASK BIT(2) +#define NVVRS_INT_SRC2_LDO_MASK BIT(3) +#define NVVRS_INT_SRC2_BIST_MASK BIT(4) +#define NVVRS_INT_SRC2_RT_CRC_MASK BIT(5) +#define NVVRS_INT_SRC2_VENDOR_MASK BIT(7) +#define NVVRS_INT_VENDOR0_MASK BIT(0) +#define NVVRS_INT_VENDOR1_MASK BIT(1) +#define NVVRS_INT_VENDOR2_MASK BIT(2) +#define NVVRS_INT_VENDOR3_MASK BIT(3) +#define NVVRS_INT_VENDOR4_MASK BIT(4) +#define NVVRS_INT_VENDOR5_MASK BIT(5) +#define NVVRS_INT_VENDOR6_MASK BIT(6) +#define NVVRS_INT_VENDOR7_MASK BIT(7) + +/* Controller Register Mask */ +#define NVVRS_REG_CTL_1_FORCE_SHDN (BIT(0) | BIT(1)) +#define NVVRS_REG_CTL_1_FORCE_ACT BIT(2) +#define NVVRS_REG_CTL_1_FORCE_INT BIT(3) +#define NVVRS_REG_CTL_2_EN_PEC BIT(0) +#define NVVRS_REG_CTL_2_REQ_PEC BIT(1) +#define NVVRS_REG_CTL_2_RTC_PU BIT(2) +#define NVVRS_REG_CTL_2_RTC_WAKE BIT(3) +#define NVVRS_REG_CTL_2_RST_DLY 0xF0 + +#define ALARM_RESET_VAL 0xffffffff +#define NVVRS_MIN_MODEL_REV 0x40 + +enum nvvrs_irq_regs { + NVVRS_IRQ_REG_INT_SRC1 = 0, + NVVRS_IRQ_REG_INT_SRC2 = 1, + NVVRS_IRQ_REG_INT_VENDOR = 2, + NVVRS_IRQ_REG_COUNT = 3, +}; + +struct nvvrs_rtc_info { + struct device *dev; + struct i2c_client *client; + struct rtc_device *rtc; + unsigned int irq; +}; + +static int nvvrs_update_bits(struct nvvrs_rtc_info *info, u8 reg, + u8 mask, u8 value) +{ + int ret; + u8 val; + + ret = i2c_smbus_read_byte_data(info->client, reg); + if (ret < 0) + return ret; + + val = (u8)ret; + val &= ~mask; + val |= (value & mask); + + return i2c_smbus_write_byte_data(info->client, reg, val); +} + +static int nvvrs_rtc_write_alarm(struct i2c_client *client, u8 *time) +{ + int ret; + + ret = i2c_smbus_write_byte_data(client, NVVRS_REG_RTC_A3, time[3]); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(client, NVVRS_REG_RTC_A2, time[2]); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(client, NVVRS_REG_RTC_A1, time[1]); + if (ret < 0) + return ret; + + return i2c_smbus_write_byte_data(client, NVVRS_REG_RTC_A0, time[0]); +} + +static int nvvrs_rtc_enable_alarm(struct nvvrs_rtc_info *info) +{ + int ret; + + /* Set RTC_WAKE bit for autonomous wake from sleep */ + ret = nvvrs_update_bits(info, NVVRS_REG_CTL_2, NVVRS_REG_CTL_2_RTC_WAKE, + NVVRS_REG_CTL_2_RTC_WAKE); + if (ret < 0) + return ret; + + /* Set RTC_PU bit for autonomous wake from shutdown */ + ret = nvvrs_update_bits(info, NVVRS_REG_CTL_2, NVVRS_REG_CTL_2_RTC_PU, + NVVRS_REG_CTL_2_RTC_PU); + if (ret < 0) + return ret; + + return 0; +} + +static int nvvrs_rtc_disable_alarm(struct nvvrs_rtc_info *info) +{ + struct i2c_client *client = info->client; + u8 val[4]; + int ret; + + /* Clear RTC_WAKE bit */ + ret = nvvrs_update_bits(info, NVVRS_REG_CTL_2, NVVRS_REG_CTL_2_RTC_WAKE, + 0); + if (ret < 0) + return ret; + + /* Clear RTC_PU bit */ + ret = nvvrs_update_bits(info, NVVRS_REG_CTL_2, NVVRS_REG_CTL_2_RTC_PU, + 0); + if (ret < 0) + return ret; + + /* Write ALARM_RESET_VAL in RTC Alarm register to disable alarm */ + val[0] = 0xff; + val[1] = 0xff; + val[2] = 0xff; + val[3] = 0xff; + + ret = nvvrs_rtc_write_alarm(client, val); + if (ret < 0) + return ret; + + return 0; +} + +static int nvvrs_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct nvvrs_rtc_info *info = dev_get_drvdata(dev); + time64_t secs = 0; + int ret; + u8 val; + + /* + * Multi-byte transfers are not supported with PEC enabled + * Read MSB first to avoid coherency issues + */ + ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_T3); + if (ret < 0) + return ret; + + val = (u8)ret; + secs |= (time64_t)val << 24; + + ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_T2); + if (ret < 0) + return ret; + + val = (u8)ret; + secs |= (time64_t)val << 16; + + ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_T1); + if (ret < 0) + return ret; + + val = (u8)ret; + secs |= (time64_t)val << 8; + + ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_T0); + if (ret < 0) + return ret; + + val = (u8)ret; + secs |= val; + + rtc_time64_to_tm(secs, tm); + + return 0; +} + +static int nvvrs_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct nvvrs_rtc_info *info = dev_get_drvdata(dev); + time64_t secs; + u8 time[4]; + int ret; + + secs = rtc_tm_to_time64(tm); + time[0] = secs & 0xff; + time[1] = (secs >> 8) & 0xff; + time[2] = (secs >> 16) & 0xff; + time[3] = (secs >> 24) & 0xff; + + ret = i2c_smbus_write_byte_data(info->client, NVVRS_REG_RTC_T3, time[3]); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(info->client, NVVRS_REG_RTC_T2, time[2]); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(info->client, NVVRS_REG_RTC_T1, time[1]); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(info->client, NVVRS_REG_RTC_T0, time[0]); + + return ret; +} + +static int nvvrs_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct nvvrs_rtc_info *info = dev_get_drvdata(dev); + time64_t alarm_val = 0; + int ret; + u8 val; + + /* Multi-byte transfers are not supported with PEC enabled */ + ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_A3); + if (ret < 0) + return ret; + + val = (u8)ret; + alarm_val |= (time64_t)val << 24; + + ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_A2); + if (ret < 0) + return ret; + + val = (u8)ret; + alarm_val |= (time64_t)val << 16; + + ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_A1); + if (ret < 0) + return ret; + + val = (u8)ret; + alarm_val |= (time64_t)val << 8; + + ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_A0); + if (ret < 0) + return ret; + + val = (u8)ret; + alarm_val |= val; + + if (alarm_val == ALARM_RESET_VAL) + alrm->enabled = 0; + else + alrm->enabled = 1; + + rtc_time64_to_tm(alarm_val, &alrm->time); + + return 0; +} + +static int nvvrs_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct nvvrs_rtc_info *info = dev_get_drvdata(dev); + time64_t secs; + u8 time[4]; + int ret; + + if (!alrm->enabled) { + ret = nvvrs_rtc_disable_alarm(info); + if (ret < 0) + return ret; + } + + ret = nvvrs_rtc_enable_alarm(info); + if (ret < 0) + return ret; + + secs = rtc_tm_to_time64(&alrm->time); + time[0] = secs & 0xff; + time[1] = (secs >> 8) & 0xff; + time[2] = (secs >> 16) & 0xff; + time[3] = (secs >> 24) & 0xff; + + ret = nvvrs_rtc_write_alarm(info->client, time); + + return ret; +} + +static int nvvrs_pseq_irq_clear(struct nvvrs_rtc_info *info) +{ + unsigned int i; + int ret; + + for (i = 0; i < NVVRS_IRQ_REG_COUNT; i++) { + ret = i2c_smbus_read_byte_data(info->client, + NVVRS_REG_INT_SRC1 + i); + if (ret < 0) { + dev_err(info->dev, "Failed to read INT_SRC%d : %d\n", + i + 1, ret); + return ret; + } + + ret = i2c_smbus_write_byte_data(info->client, + NVVRS_REG_INT_SRC1 + i, + (u8)ret); + if (ret < 0) { + dev_err(info->dev, "Failed to clear INT_SRC%d : %d\n", + i + 1, ret); + return ret; + } + } + + return 0; +} + +static irqreturn_t nvvrs_rtc_irq_handler(int irq, void *data) +{ + struct nvvrs_rtc_info *info = data; + int ret; + + /* Check for RTC alarm interrupt */ + ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_INT_SRC1); + if (ret < 0) + return IRQ_NONE; + + if (ret & NVVRS_INT_SRC1_RTC_MASK) { + rtc_lock(info->rtc); + rtc_update_irq(info->rtc, 1, RTC_IRQF | RTC_AF); + rtc_unlock(info->rtc); + } + + /* Clear all interrupts */ + if (nvvrs_pseq_irq_clear(info) < 0) + return IRQ_NONE; + + return IRQ_HANDLED; +} + +static int nvvrs_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + /* + * This hardware does not support enabling/disabling the alarm IRQ + * independently. The alarm is disabled by clearing the alarm time + * via set_alarm(). + */ + return 0; +} + +static const struct rtc_class_ops nvvrs_rtc_ops = { + .read_time = nvvrs_rtc_read_time, + .set_time = nvvrs_rtc_set_time, + .read_alarm = nvvrs_rtc_read_alarm, + .set_alarm = nvvrs_rtc_set_alarm, + .alarm_irq_enable = nvvrs_rtc_alarm_irq_enable, +}; + +static int nvvrs_pseq_vendor_info(struct nvvrs_rtc_info *info) +{ + struct i2c_client *client = info->client; + u8 vendor_id, model_rev; + int ret; + + ret = i2c_smbus_read_byte_data(client, NVVRS_REG_VENDOR_ID); + if (ret < 0) + return dev_err_probe(&client->dev, ret, + "Failed to read Vendor ID\n"); + + vendor_id = (u8)ret; + + ret = i2c_smbus_read_byte_data(client, NVVRS_REG_MODEL_REV); + if (ret < 0) + return dev_err_probe(&client->dev, ret, + "Failed to read Model Revision\n"); + + model_rev = (u8)ret; + + if (model_rev < NVVRS_MIN_MODEL_REV) { + return dev_err_probe(&client->dev, -ENODEV, + "Chip revision 0x%02x is not supported!\n", + model_rev); + } + + dev_dbg(&client->dev, "NVVRS Vendor ID: 0x%02x, Model Rev: 0x%02x\n", + vendor_id, model_rev); + + return 0; +} + +static int nvvrs_rtc_probe(struct i2c_client *client) +{ + struct nvvrs_rtc_info *info; + int ret; + + info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + if (client->irq <= 0) + return dev_err_probe(&client->dev, -EINVAL, "No IRQ specified\n"); + + info->irq = client->irq; + info->dev = &client->dev; + client->flags |= I2C_CLIENT_PEC; + i2c_set_clientdata(client, info); + info->client = client; + + /* Check vendor info */ + if (nvvrs_pseq_vendor_info(info) < 0) + return dev_err_probe(&client->dev, -EINVAL, + "Failed to get vendor info\n"); + + /* Clear any pending IRQs before requesting IRQ handler */ + if (nvvrs_pseq_irq_clear(info) < 0) + return dev_err_probe(&client->dev, -EINVAL, + "Failed to clear interrupts\n"); + + /* Allocate RTC device */ + info->rtc = devm_rtc_allocate_device(info->dev); + if (IS_ERR(info->rtc)) + return PTR_ERR(info->rtc); + + info->rtc->ops = &nvvrs_rtc_ops; + info->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; + info->rtc->range_max = RTC_TIMESTAMP_END_2099; + + /* Request RTC IRQ */ + ret = devm_request_threaded_irq(info->dev, info->irq, NULL, + nvvrs_rtc_irq_handler, IRQF_ONESHOT, + "nvvrs-rtc", info); + if (ret < 0) { + dev_err_probe(info->dev, ret, "Failed to request RTC IRQ\n"); + return ret; + } + + /* RTC as a wakeup source */ + devm_device_init_wakeup(info->dev); + + return devm_rtc_register_device(info->rtc); +} + +#ifdef CONFIG_PM_SLEEP +static int nvvrs_rtc_suspend(struct device *dev) +{ + struct nvvrs_rtc_info *info = dev_get_drvdata(dev); + int ret; + + if (device_may_wakeup(dev)) { + /* Set RTC_WAKE bit for auto wake system from suspend state */ + ret = nvvrs_update_bits(info, NVVRS_REG_CTL_2, + NVVRS_REG_CTL_2_RTC_WAKE, + NVVRS_REG_CTL_2_RTC_WAKE); + if (ret < 0) { + dev_err(info->dev, "Failed to set RTC_WAKE bit (%d)\n", + ret); + return ret; + } + + return enable_irq_wake(info->irq); + } + + return 0; +} + +static int nvvrs_rtc_resume(struct device *dev) +{ + struct nvvrs_rtc_info *info = dev_get_drvdata(dev); + int ret; + + if (device_may_wakeup(dev)) { + /* Clear FORCE_ACT bit */ + ret = nvvrs_update_bits(info, NVVRS_REG_CTL_1, + NVVRS_REG_CTL_1_FORCE_ACT, 0); + if (ret < 0) { + dev_err(info->dev, "Failed to clear FORCE_ACT bit (%d)\n", + ret); + return ret; + } + + return disable_irq_wake(info->irq); + } + + return 0; +} + +#endif +static SIMPLE_DEV_PM_OPS(nvvrs_rtc_pm_ops, nvvrs_rtc_suspend, nvvrs_rtc_resume); + +static const struct of_device_id nvvrs_rtc_of_match[] = { + { .compatible = "nvidia,vrs-10" }, + { }, +}; +MODULE_DEVICE_TABLE(of, nvvrs_rtc_of_match); + +static struct i2c_driver nvvrs_rtc_driver = { + .driver = { + .name = "rtc-nvidia-vrs10", + .pm = &nvvrs_rtc_pm_ops, + .of_match_table = nvvrs_rtc_of_match, + }, + .probe = nvvrs_rtc_probe, +}; + +module_i2c_driver(nvvrs_rtc_driver); + +MODULE_AUTHOR("Shubhi Garg <shgarg@nvidia.com>"); +MODULE_DESCRIPTION("NVIDIA Voltage Regulator Specification RTC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-pic32.c b/drivers/rtc/rtc-pic32.c index 2812da2c50c5..52c11532bc3a 100644 --- a/drivers/rtc/rtc-pic32.c +++ b/drivers/rtc/rtc-pic32.c @@ -340,8 +340,6 @@ static int pic32_rtc_probe(struct platform_device *pdev) if (ret) goto err_nortc; - pdata->rtc->max_user_freq = 128; - pic32_rtc_setfreq(&pdev->dev, 1); ret = devm_request_irq(&pdev->dev, pdata->alarm_irq, pic32_rtc_alarmirq, 0, diff --git a/drivers/rtc/rtc-renesas-rtca3.c b/drivers/rtc/rtc-renesas-rtca3.c index ab816bdf0d77..cbabaa4dc96a 100644 --- a/drivers/rtc/rtc-renesas-rtca3.c +++ b/drivers/rtc/rtc-renesas-rtca3.c @@ -726,7 +726,7 @@ static int rtca3_probe(struct platform_device *pdev) if (ret) return ret; - priv->rstc = devm_reset_control_get_shared(dev, NULL); + priv->rstc = devm_reset_control_array_get_shared(dev); if (IS_ERR(priv->rstc)) return PTR_ERR(priv->rstc); @@ -772,7 +772,6 @@ static int rtca3_probe(struct platform_device *pdev) return PTR_ERR(priv->rtc_dev); priv->rtc_dev->ops = &rtca3_ops; - priv->rtc_dev->max_user_freq = 256; priv->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_2000; priv->rtc_dev->range_max = RTC_TIMESTAMP_END_2099; diff --git a/drivers/rtc/rtc-rv3028.c b/drivers/rtc/rtc-rv3028.c index c2a531f0e125..d96f6bb68850 100644 --- a/drivers/rtc/rtc-rv3028.c +++ b/drivers/rtc/rtc-rv3028.c @@ -1023,8 +1023,6 @@ static int rv3028_probe(struct i2c_client *client) eeprom_cfg.priv = rv3028; devm_rtc_nvmem_register(rv3028->rtc, &eeprom_cfg); - rv3028->rtc->max_user_freq = 1; - #ifdef CONFIG_COMMON_CLK rv3028_clkout_register_clk(rv3028, client); #endif diff --git a/drivers/rtc/rtc-rv3032.c b/drivers/rtc/rtc-rv3032.c index b8376bd1d905..6c09da7738e1 100644 --- a/drivers/rtc/rtc-rv3032.c +++ b/drivers/rtc/rtc-rv3032.c @@ -968,8 +968,6 @@ static int rv3032_probe(struct i2c_client *client) eeprom_cfg.priv = rv3032; devm_rtc_nvmem_register(rv3032->rtc, &eeprom_cfg); - rv3032->rtc->max_user_freq = 1; - #ifdef CONFIG_COMMON_CLK rv3032_clkout_register_clk(rv3032, client); #endif diff --git a/drivers/rtc/rtc-rv8803.c b/drivers/rtc/rtc-rv8803.c index 1327251e527c..4e9e04cbec89 100644 --- a/drivers/rtc/rtc-rv8803.c +++ b/drivers/rtc/rtc-rv8803.c @@ -738,8 +738,6 @@ static int rv8803_probe(struct i2c_client *client) devm_rtc_nvmem_register(rv8803->rtc, &nvmem_cfg); - rv8803->rtc->max_user_freq = 1; - return 0; } diff --git a/drivers/rtc/rtc-rx6110.c b/drivers/rtc/rtc-rx6110.c index 7c423d672adb..07bf35ac8d79 100644 --- a/drivers/rtc/rtc-rx6110.c +++ b/drivers/rtc/rtc-rx6110.c @@ -324,8 +324,6 @@ static int rx6110_probe(struct rx6110_data *rx6110, struct device *dev) if (err) return err; - rx6110->rtc->max_user_freq = 1; - return 0; } diff --git a/drivers/rtc/rtc-rx8010.c b/drivers/rtc/rtc-rx8010.c index 2b6198d1cf81..171240e50f48 100644 --- a/drivers/rtc/rtc-rx8010.c +++ b/drivers/rtc/rtc-rx8010.c @@ -412,7 +412,6 @@ static int rx8010_probe(struct i2c_client *client) } rx8010->rtc->ops = &rx8010_rtc_ops; - rx8010->rtc->max_user_freq = 1; rx8010->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; rx8010->rtc->range_max = RTC_TIMESTAMP_END_2099; diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index 7e9f7cb90c28..ced6e7adfe8d 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -565,8 +565,6 @@ static int rx8025_probe(struct i2c_client *client) clear_bit(RTC_FEATURE_ALARM, rx8025->rtc->features); } - rx8025->rtc->max_user_freq = 1; - set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rx8025->rtc->features); clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rx8025->rtc->features); diff --git a/drivers/rtc/rtc-s35390a.c b/drivers/rtc/rtc-s35390a.c index 3408d2ab2741..07bd983b5692 100644 --- a/drivers/rtc/rtc-s35390a.c +++ b/drivers/rtc/rtc-s35390a.c @@ -66,7 +66,7 @@ struct s35390a { int twentyfourhour; }; -static int s35390a_set_reg(struct s35390a *s35390a, int reg, char *buf, int len) +static int s35390a_set_reg(struct s35390a *s35390a, int reg, u8 *buf, int len) { struct i2c_client *client = s35390a->client[reg]; struct i2c_msg msg[] = { @@ -83,7 +83,7 @@ static int s35390a_set_reg(struct s35390a *s35390a, int reg, char *buf, int len) return 0; } -static int s35390a_get_reg(struct s35390a *s35390a, int reg, char *buf, int len) +static int s35390a_get_reg(struct s35390a *s35390a, int reg, u8 *buf, int len) { struct i2c_client *client = s35390a->client[reg]; struct i2c_msg msg[] = { @@ -168,7 +168,7 @@ static int s35390a_read_status(struct s35390a *s35390a, char *status1) static int s35390a_disable_test_mode(struct s35390a *s35390a) { - char buf[1]; + u8 buf[1]; if (s35390a_get_reg(s35390a, S35390A_CMD_STATUS2, buf, sizeof(buf)) < 0) return -EIO; @@ -210,7 +210,7 @@ static int s35390a_rtc_set_time(struct device *dev, struct rtc_time *tm) struct i2c_client *client = to_i2c_client(dev); struct s35390a *s35390a = i2c_get_clientdata(client); int i; - char buf[7], status; + u8 buf[7], status; dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d mday=%d, " "mon=%d, year=%d, wday=%d\n", __func__, tm->tm_sec, @@ -239,7 +239,7 @@ static int s35390a_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct i2c_client *client = to_i2c_client(dev); struct s35390a *s35390a = i2c_get_clientdata(client); - char buf[7], status; + u8 buf[7], status; int i, err; if (s35390a_read_status(s35390a, &status) == 1) @@ -273,7 +273,7 @@ static int s35390a_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) { struct i2c_client *client = to_i2c_client(dev); struct s35390a *s35390a = i2c_get_clientdata(client); - char buf[3], sts = 0; + u8 buf[3], sts = 0; int err, i; dev_dbg(&client->dev, "%s: alm is secs=%d, mins=%d, hours=%d mday=%d, "\ @@ -326,7 +326,7 @@ static int s35390a_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) { struct i2c_client *client = to_i2c_client(dev); struct s35390a *s35390a = i2c_get_clientdata(client); - char buf[3], sts; + u8 buf[3], sts; int i, err; err = s35390a_get_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts)); @@ -383,7 +383,7 @@ static int s35390a_rtc_ioctl(struct device *dev, unsigned int cmd, { struct i2c_client *client = to_i2c_client(dev); struct s35390a *s35390a = i2c_get_clientdata(client); - char sts; + u8 sts; int err; switch (cmd) { @@ -422,7 +422,7 @@ static int s35390a_probe(struct i2c_client *client) unsigned int i; struct s35390a *s35390a; struct rtc_device *rtc; - char buf, status1; + u8 buf, status1; struct device *dev = &client->dev; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index 1ad93648d69c..26b2f4184ecc 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -40,8 +40,6 @@ #define RTC_DEF_DIVIDER (32768 - 1) #define RTC_DEF_TRIM 0 -#define RTC_FREQ 1024 - static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) { @@ -202,7 +200,6 @@ int sa1100_rtc_init(struct platform_device *pdev, struct sa1100_rtc *info) } info->rtc->ops = &sa1100_rtc_ops; - info->rtc->max_user_freq = RTC_FREQ; info->rtc->range_max = U32_MAX; ret = devm_rtc_register_device(info->rtc); diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index 619800a00479..0510dc64c3e2 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -423,7 +423,6 @@ static int __init sh_rtc_probe(struct platform_device *pdev) writeb(tmp, rtc->regbase + RCR1); rtc->rtc_dev->ops = &sh_rtc_ops; - rtc->rtc_dev->max_user_freq = 256; if (rtc->capabilities & RTC_CAP_4_DIGIT_YEAR) { rtc->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_1900; diff --git a/drivers/rtc/rtc-tegra.c b/drivers/rtc/rtc-tegra.c index 46788db89953..528e32b7d101 100644 --- a/drivers/rtc/rtc-tegra.c +++ b/drivers/rtc/rtc-tegra.c @@ -274,6 +274,12 @@ static const struct of_device_id tegra_rtc_dt_match[] = { }; MODULE_DEVICE_TABLE(of, tegra_rtc_dt_match); +static const struct acpi_device_id tegra_rtc_acpi_match[] = { + { "NVDA0280" }, + { } +}; +MODULE_DEVICE_TABLE(acpi, tegra_rtc_acpi_match); + static int tegra_rtc_probe(struct platform_device *pdev) { struct tegra_rtc_info *info; @@ -300,13 +306,11 @@ static int tegra_rtc_probe(struct platform_device *pdev) info->rtc->ops = &tegra_rtc_ops; info->rtc->range_max = U32_MAX; - info->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(info->clk)) - return PTR_ERR(info->clk); - - ret = clk_prepare_enable(info->clk); - if (ret < 0) - return ret; + if (dev_of_node(&pdev->dev)) { + info->clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(info->clk)) + return PTR_ERR(info->clk); + } /* set context info */ info->pdev = pdev; @@ -324,32 +328,18 @@ static int tegra_rtc_probe(struct platform_device *pdev) ret = devm_request_irq(&pdev->dev, info->irq, tegra_rtc_irq_handler, IRQF_TRIGGER_HIGH, dev_name(&pdev->dev), &pdev->dev); - if (ret) { - dev_err(&pdev->dev, "failed to request interrupt: %d\n", ret); - goto disable_clk; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, "failed to request interrupt\n"); ret = devm_rtc_register_device(info->rtc); if (ret) - goto disable_clk; + return ret; dev_notice(&pdev->dev, "Tegra internal Real Time Clock\n"); return 0; - -disable_clk: - clk_disable_unprepare(info->clk); - return ret; -} - -static void tegra_rtc_remove(struct platform_device *pdev) -{ - struct tegra_rtc_info *info = platform_get_drvdata(pdev); - - clk_disable_unprepare(info->clk); } -#ifdef CONFIG_PM_SLEEP static int tegra_rtc_suspend(struct device *dev) { struct tegra_rtc_info *info = dev_get_drvdata(dev); @@ -387,9 +377,8 @@ static int tegra_rtc_resume(struct device *dev) return 0; } -#endif -static SIMPLE_DEV_PM_OPS(tegra_rtc_pm_ops, tegra_rtc_suspend, tegra_rtc_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(tegra_rtc_pm_ops, tegra_rtc_suspend, tegra_rtc_resume); static void tegra_rtc_shutdown(struct platform_device *pdev) { @@ -399,12 +388,12 @@ static void tegra_rtc_shutdown(struct platform_device *pdev) static struct platform_driver tegra_rtc_driver = { .probe = tegra_rtc_probe, - .remove = tegra_rtc_remove, .shutdown = tegra_rtc_shutdown, .driver = { .name = "tegra_rtc", .of_match_table = tegra_rtc_dt_match, - .pm = &tegra_rtc_pm_ops, + .acpi_match_table = tegra_rtc_acpi_match, + .pm = pm_sleep_ptr(&tegra_rtc_pm_ops), }, }; module_platform_driver(tegra_rtc_driver); diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 55c1db816534..fb68738dfb9b 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -2052,8 +2052,14 @@ EXPORT_SYMBOL(sdw_clear_slave_status); int sdw_bpt_send_async(struct sdw_bus *bus, struct sdw_slave *slave, struct sdw_bpt_msg *msg) { - if (msg->len > SDW_BPT_MSG_MAX_BYTES) { - dev_err(bus->dev, "Invalid BPT message length %d\n", msg->len); + int len = 0; + int i; + + for (i = 0; i < msg->sections; i++) + len += msg->sec[i].len; + + if (len > SDW_BPT_MSG_MAX_BYTES) { + dev_err(bus->dev, "Invalid BPT message length %d\n", len); return -EINVAL; } diff --git a/drivers/soundwire/bus.h b/drivers/soundwire/bus.h index 02651fbb683a..8115c64dd48e 100644 --- a/drivers/soundwire/bus.h +++ b/drivers/soundwire/bus.h @@ -73,21 +73,31 @@ struct sdw_msg { }; /** - * struct sdw_btp_msg - Message structure + * struct sdw_btp_section - Message section structure * @addr: Start Register address accessed in the Slave * @len: number of bytes to transfer. More than 64Kb can be transferred * but a practical limit of SDW_BPT_MSG_MAX_BYTES is enforced. - * @dev_num: Slave device number - * @flags: transfer flags, indicate if xfer is read or write - * @buf: message data buffer (filled by host for write, filled + * @buf: section data buffer (filled by host for write, filled * by Peripheral hardware for reads) */ -struct sdw_bpt_msg { +struct sdw_bpt_section { u32 addr; u32 len; + u8 *buf; +}; + +/** + * struct sdw_btp_msg - Message structure + * @sec: Pointer to array of sections + * @sections: Number of sections in the array + * @dev_num: Slave device number + * @flags: transfer flags, indicate if xfer is read or write + */ +struct sdw_bpt_msg { + struct sdw_bpt_section *sec; + int sections; u8 dev_num; u8 flags; - u8 *buf; }; #define SDW_DOUBLE_RATE_FACTOR 2 diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index 21bb491d026b..a106e5e482c8 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -2094,6 +2094,36 @@ static unsigned int sdw_cdns_read_pdi1_buffer_size(unsigned int actual_data_size return total * 2; } +int sdw_cdns_bpt_find_bandwidth(int command, /* 0: write, 1: read */ + int row, int col, int frame_rate, + unsigned int *tx_dma_bandwidth, + unsigned int *rx_dma_bandwidth) +{ + unsigned int bpt_bits = row * (col - 1); + unsigned int bpt_bytes = bpt_bits >> 3; + unsigned int pdi0_buffer_size; + unsigned int pdi1_buffer_size; + unsigned int data_per_frame; + + data_per_frame = sdw_cdns_bra_actual_data_size(bpt_bytes); + if (!data_per_frame) + return -EINVAL; + + if (command == 0) { + pdi0_buffer_size = sdw_cdns_write_pdi0_buffer_size(data_per_frame); + pdi1_buffer_size = SDW_CDNS_WRITE_PDI1_BUFFER_SIZE; + } else { + pdi0_buffer_size = SDW_CDNS_READ_PDI0_BUFFER_SIZE; + pdi1_buffer_size = sdw_cdns_read_pdi1_buffer_size(data_per_frame); + } + + *tx_dma_bandwidth = pdi0_buffer_size * 8 * frame_rate; + *rx_dma_bandwidth = pdi1_buffer_size * 8 * frame_rate; + + return 0; +} +EXPORT_SYMBOL(sdw_cdns_bpt_find_bandwidth); + int sdw_cdns_bpt_find_buffer_sizes(int command, /* 0: write, 1: read */ int row, int col, unsigned int data_bytes, unsigned int requested_bytes_per_frame, @@ -2114,9 +2144,6 @@ int sdw_cdns_bpt_find_buffer_sizes(int command, /* 0: write, 1: read */ if (!actual_bpt_bytes) return -EINVAL; - if (data_bytes < actual_bpt_bytes) - actual_bpt_bytes = data_bytes; - /* * the caller may want to set the number of bytes per frame, * allow when possible @@ -2126,6 +2153,9 @@ int sdw_cdns_bpt_find_buffer_sizes(int command, /* 0: write, 1: read */ *data_per_frame = actual_bpt_bytes; + if (data_bytes < actual_bpt_bytes) + actual_bpt_bytes = data_bytes; + if (command == 0) { /* * for writes we need to send all the data_bytes per frame, @@ -2294,17 +2324,20 @@ static int sdw_cdns_prepare_read_pd0_buffer(u8 *header, unsigned int header_size #define CDNS_BPT_ROLLING_COUNTER_START 1 -int sdw_cdns_prepare_write_dma_buffer(u8 dev_num, u32 start_register, u8 *data, int data_size, - int data_per_frame, u8 *dma_buffer, int dma_buffer_size, - int *dma_buffer_total_bytes) +int sdw_cdns_prepare_write_dma_buffer(u8 dev_num, struct sdw_bpt_section *sec, int num_sec, + int data_per_frame, u8 *dma_buffer, + int dma_buffer_size, int *dma_buffer_total_bytes) { int total_dma_data_written = 0; u8 *p_dma_buffer = dma_buffer; u8 header[SDW_CDNS_BRA_HDR]; + unsigned int start_register; + unsigned int section_size; int dma_data_written; - u8 *p_data = data; + u8 *p_data; u8 counter; int ret; + int i; counter = CDNS_BPT_ROLLING_COUNTER_START; @@ -2312,47 +2345,57 @@ int sdw_cdns_prepare_write_dma_buffer(u8 dev_num, u32 start_register, u8 *data, header[0] |= GENMASK(7, 6); /* header is active */ header[0] |= (dev_num << 2); - while (data_size >= data_per_frame) { - header[1] = data_per_frame; - header[2] = start_register >> 24 & 0xFF; - header[3] = start_register >> 16 & 0xFF; - header[4] = start_register >> 8 & 0xFF; - header[5] = start_register >> 0 & 0xFF; - - ret = sdw_cdns_prepare_write_pd0_buffer(header, SDW_CDNS_BRA_HDR, - p_data, data_per_frame, - p_dma_buffer, dma_buffer_size, - &dma_data_written, counter); - if (ret < 0) - return ret; + for (i = 0; i < num_sec; i++) { + start_register = sec[i].addr; + section_size = sec[i].len; + p_data = sec[i].buf; - counter++; + while (section_size >= data_per_frame) { + header[1] = data_per_frame; + header[2] = start_register >> 24 & 0xFF; + header[3] = start_register >> 16 & 0xFF; + header[4] = start_register >> 8 & 0xFF; + header[5] = start_register >> 0 & 0xFF; - p_data += data_per_frame; - data_size -= data_per_frame; + ret = sdw_cdns_prepare_write_pd0_buffer(header, SDW_CDNS_BRA_HDR, + p_data, data_per_frame, + p_dma_buffer, dma_buffer_size, + &dma_data_written, counter); + if (ret < 0) + return ret; - p_dma_buffer += dma_data_written; - dma_buffer_size -= dma_data_written; - total_dma_data_written += dma_data_written; + counter++; - start_register += data_per_frame; - } + p_data += data_per_frame; + section_size -= data_per_frame; - if (data_size) { - header[1] = data_size; - header[2] = start_register >> 24 & 0xFF; - header[3] = start_register >> 16 & 0xFF; - header[4] = start_register >> 8 & 0xFF; - header[5] = start_register >> 0 & 0xFF; + p_dma_buffer += dma_data_written; + dma_buffer_size -= dma_data_written; + total_dma_data_written += dma_data_written; - ret = sdw_cdns_prepare_write_pd0_buffer(header, SDW_CDNS_BRA_HDR, - p_data, data_size, - p_dma_buffer, dma_buffer_size, - &dma_data_written, counter); - if (ret < 0) - return ret; + start_register += data_per_frame; + } - total_dma_data_written += dma_data_written; + if (section_size) { + header[1] = section_size; + header[2] = start_register >> 24 & 0xFF; + header[3] = start_register >> 16 & 0xFF; + header[4] = start_register >> 8 & 0xFF; + header[5] = start_register >> 0 & 0xFF; + + ret = sdw_cdns_prepare_write_pd0_buffer(header, SDW_CDNS_BRA_HDR, + p_data, section_size, + p_dma_buffer, dma_buffer_size, + &dma_data_written, counter); + if (ret < 0) + return ret; + + counter++; + + p_dma_buffer += dma_data_written; + dma_buffer_size -= dma_data_written; + total_dma_data_written += dma_data_written; + } } *dma_buffer_total_bytes = total_dma_data_written; @@ -2361,16 +2404,19 @@ int sdw_cdns_prepare_write_dma_buffer(u8 dev_num, u32 start_register, u8 *data, } EXPORT_SYMBOL(sdw_cdns_prepare_write_dma_buffer); -int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, u32 start_register, int data_size, +int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, struct sdw_bpt_section *sec, int num_sec, int data_per_frame, u8 *dma_buffer, int dma_buffer_size, - int *dma_buffer_total_bytes) + int *dma_buffer_total_bytes, unsigned int fake_size) { int total_dma_data_written = 0; u8 *p_dma_buffer = dma_buffer; u8 header[SDW_CDNS_BRA_HDR]; + unsigned int start_register; + unsigned int data_size; int dma_data_written; u8 counter; int ret; + int i; counter = CDNS_BPT_ROLLING_COUNTER_START; @@ -2378,13 +2424,58 @@ int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, u32 start_register, int data_si header[0] |= GENMASK(7, 6); /* header is active */ header[0] |= (dev_num << 2); - while (data_size >= data_per_frame) { - header[1] = data_per_frame; - header[2] = start_register >> 24 & 0xFF; - header[3] = start_register >> 16 & 0xFF; - header[4] = start_register >> 8 & 0xFF; - header[5] = start_register >> 0 & 0xFF; + for (i = 0; i < num_sec; i++) { + start_register = sec[i].addr; + data_size = sec[i].len; + while (data_size >= data_per_frame) { + header[1] = data_per_frame; + header[2] = start_register >> 24 & 0xFF; + header[3] = start_register >> 16 & 0xFF; + header[4] = start_register >> 8 & 0xFF; + header[5] = start_register >> 0 & 0xFF; + + ret = sdw_cdns_prepare_read_pd0_buffer(header, SDW_CDNS_BRA_HDR, + p_dma_buffer, dma_buffer_size, + &dma_data_written, counter); + if (ret < 0) + return ret; + + counter++; + + data_size -= data_per_frame; + + p_dma_buffer += dma_data_written; + dma_buffer_size -= dma_data_written; + total_dma_data_written += dma_data_written; + + start_register += data_per_frame; + } + + if (data_size) { + header[1] = data_size; + header[2] = start_register >> 24 & 0xFF; + header[3] = start_register >> 16 & 0xFF; + header[4] = start_register >> 8 & 0xFF; + header[5] = start_register >> 0 & 0xFF; + + ret = sdw_cdns_prepare_read_pd0_buffer(header, SDW_CDNS_BRA_HDR, + p_dma_buffer, dma_buffer_size, + &dma_data_written, counter); + if (ret < 0) + return ret; + + counter++; + p_dma_buffer += dma_data_written; + dma_buffer_size -= dma_data_written; + total_dma_data_written += dma_data_written; + } + } + + /* Add fake frame */ + header[0] &= ~GENMASK(7, 6); /* Set inactive flag in BPT/BRA frame heade */ + while (fake_size >= data_per_frame) { + header[1] = data_per_frame; ret = sdw_cdns_prepare_read_pd0_buffer(header, SDW_CDNS_BRA_HDR, p_dma_buffer, dma_buffer_size, &dma_data_written, counter); @@ -2393,28 +2484,24 @@ int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, u32 start_register, int data_si counter++; - data_size -= data_per_frame; - + fake_size -= data_per_frame; p_dma_buffer += dma_data_written; dma_buffer_size -= dma_data_written; total_dma_data_written += dma_data_written; - - start_register += data_per_frame; } - if (data_size) { - header[1] = data_size; - header[2] = start_register >> 24 & 0xFF; - header[3] = start_register >> 16 & 0xFF; - header[4] = start_register >> 8 & 0xFF; - header[5] = start_register >> 0 & 0xFF; - + if (fake_size) { + header[1] = fake_size; ret = sdw_cdns_prepare_read_pd0_buffer(header, SDW_CDNS_BRA_HDR, p_dma_buffer, dma_buffer_size, &dma_data_written, counter); if (ret < 0) return ret; + counter++; + + p_dma_buffer += dma_data_written; + dma_buffer_size -= dma_data_written; total_dma_data_written += dma_data_written; } @@ -2495,14 +2582,14 @@ int sdw_cdns_check_write_response(struct device *dev, u8 *dma_buffer, ret = check_frame_start(header, counter); if (ret < 0) { dev_err(dev, "%s: bad frame %d/%d start header %x\n", - __func__, i, num_frames, header); + __func__, i + 1, num_frames, header); return ret; } ret = check_frame_end(footer); if (ret < 0) { dev_err(dev, "%s: bad frame %d/%d end footer %x\n", - __func__, i, num_frames, footer); + __func__, i + 1, num_frames, footer); return ret; } @@ -2549,9 +2636,12 @@ static u8 extract_read_data(u32 *data, int num_bytes, u8 *buffer) } int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buffer_size, - u8 *buffer, int buffer_size, int num_frames, int data_per_frame) + struct sdw_bpt_section *sec, int num_sec, int num_frames, + int data_per_frame) { int total_num_bytes = 0; + int buffer_size = 0; + int sec_index; u32 *p_data; u8 *p_buf; int counter; @@ -2565,7 +2655,10 @@ int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buf counter = CDNS_BPT_ROLLING_COUNTER_START; p_data = (u32 *)dma_buffer; - p_buf = buffer; + + sec_index = 0; + p_buf = sec[sec_index].buf; + buffer_size = sec[sec_index].len; for (i = 0; i < num_frames; i++) { header = *p_data++; @@ -2573,7 +2666,7 @@ int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buf ret = check_frame_start(header, counter); if (ret < 0) { dev_err(dev, "%s: bad frame %d/%d start header %x\n", - __func__, i, num_frames, header); + __func__, i + 1, num_frames, header); return ret; } @@ -2588,7 +2681,7 @@ int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buf if (crc != expected_crc) { dev_err(dev, "%s: bad frame %d/%d crc %#x expected %#x\n", - __func__, i, num_frames, crc, expected_crc); + __func__, i + 1, num_frames, crc, expected_crc); return -EIO; } @@ -2599,12 +2692,24 @@ int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buf ret = check_frame_end(footer); if (ret < 0) { dev_err(dev, "%s: bad frame %d/%d end footer %x\n", - __func__, i, num_frames, footer); + __func__, i + 1, num_frames, footer); return ret; } counter++; counter &= GENMASK(3, 0); + + if (buffer_size == total_num_bytes && (i + 1) < num_frames) { + sec_index++; + if (sec_index >= num_sec) { + dev_err(dev, "%s: incorrect section index %d i %d\n", + __func__, sec_index, i); + return -EINVAL; + } + p_buf = sec[sec_index].buf; + buffer_size = sec[sec_index].len; + total_num_bytes = 0; + } } return 0; } diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h index 9373426c7f63..668f807cff4b 100644 --- a/drivers/soundwire/cadence_master.h +++ b/drivers/soundwire/cadence_master.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ /* Copyright(c) 2015-17 Intel Corporation. */ #include <sound/soc.h> +#include "bus.h" #ifndef __SDW_CADENCE_H #define __SDW_CADENCE_H @@ -209,23 +210,29 @@ void sdw_cdns_config_update(struct sdw_cdns *cdns); int sdw_cdns_config_update_set_wait(struct sdw_cdns *cdns); /* SoundWire BPT/BRA helpers to format data */ +int sdw_cdns_bpt_find_bandwidth(int command, /* 0: write, 1: read */ + int row, int col, int frame_rate, + unsigned int *tx_dma_bandwidth, + unsigned int *rx_dma_bandwidth); + int sdw_cdns_bpt_find_buffer_sizes(int command, /* 0: write, 1: read */ int row, int col, unsigned int data_bytes, unsigned int requested_bytes_per_frame, unsigned int *data_per_frame, unsigned int *pdi0_buffer_size, unsigned int *pdi1_buffer_size, unsigned int *num_frames); -int sdw_cdns_prepare_write_dma_buffer(u8 dev_num, u32 start_register, u8 *data, int data_size, - int data_per_frame, u8 *dma_buffer, int dma_buffer_size, - int *dma_buffer_total_bytes); +int sdw_cdns_prepare_write_dma_buffer(u8 dev_num, struct sdw_bpt_section *sec, int num_sec, + int data_per_frame, u8 *dma_buffer, + int dma_buffer_size, int *dma_buffer_total_bytes); -int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, u32 start_register, int data_size, +int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, struct sdw_bpt_section *sec, int num_sec, int data_per_frame, u8 *dma_buffer, int dma_buffer_size, - int *dma_buffer_total_bytes); + int *dma_buffer_total_bytes, unsigned int fake_size); int sdw_cdns_check_write_response(struct device *dev, u8 *dma_buffer, int dma_buffer_size, int num_frames); int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buffer_size, - u8 *buffer, int buffer_size, int num_frames, int data_per_frame); + struct sdw_bpt_section *sec, int num_sec, int num_frames, + int data_per_frame); #endif /* __SDW_CADENCE_H */ diff --git a/drivers/soundwire/debugfs.c b/drivers/soundwire/debugfs.c index 1e0f9318b616..6068011dd0d9 100644 --- a/drivers/soundwire/debugfs.c +++ b/drivers/soundwire/debugfs.c @@ -222,15 +222,23 @@ DEFINE_DEBUGFS_ATTRIBUTE(set_num_bytes_fops, NULL, static int do_bpt_sequence(struct sdw_slave *slave, bool write, u8 *buffer) { struct sdw_bpt_msg msg = {0}; + struct sdw_bpt_section *sec; - msg.addr = start_addr; - msg.len = num_bytes; + sec = kcalloc(1, sizeof(*sec), GFP_KERNEL); + if (!sec) + return -ENOMEM; + msg.sections = 1; + + sec[0].addr = start_addr; + sec[0].len = num_bytes; + + msg.sec = sec; msg.dev_num = slave->dev_num; if (write) msg.flags = SDW_MSG_FLAG_WRITE; else msg.flags = SDW_MSG_FLAG_READ; - msg.buf = buffer; + sec[0].buf = buffer; return sdw_bpt_send_sync(slave->bus, slave, &msg); } diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c index c18f0c16f929..530ac66ac6fa 100644 --- a/drivers/soundwire/generic_bandwidth_allocation.c +++ b/drivers/soundwire/generic_bandwidth_allocation.c @@ -124,6 +124,9 @@ static void sdw_compute_dp0_port_params(struct sdw_bus *bus) struct sdw_master_runtime *m_rt; list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) { + /* DP0 is for BPT only */ + if (m_rt->stream->type != SDW_STREAM_BPT) + continue; sdw_compute_dp0_master_ports(m_rt); sdw_compute_dp0_slave_ports(m_rt); } diff --git a/drivers/soundwire/intel_ace2x.c b/drivers/soundwire/intel_ace2x.c index 5d08364ad6d1..1ed0251d2592 100644 --- a/drivers/soundwire/intel_ace2x.c +++ b/drivers/soundwire/intel_ace2x.c @@ -44,6 +44,8 @@ static int sdw_slave_bpt_stream_add(struct sdw_slave *slave, struct sdw_stream_r return ret; } +#define READ_PDI1_MIN_SIZE 12 + static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave *slave, struct sdw_bpt_msg *msg) { @@ -53,19 +55,31 @@ static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave * struct sdw_stream_runtime *stream; struct sdw_stream_config sconfig; struct sdw_port_config *pconfig; + unsigned int pdi0_buf_size_pre_frame; + unsigned int pdi1_buf_size_pre_frame; + unsigned int pdi0_buffer_size_; + unsigned int pdi1_buffer_size_; unsigned int pdi0_buffer_size; unsigned int tx_dma_bandwidth; unsigned int pdi1_buffer_size; unsigned int rx_dma_bandwidth; + unsigned int fake_num_frames; unsigned int data_per_frame; unsigned int tx_total_bytes; struct sdw_cdns_pdi *pdi0; struct sdw_cdns_pdi *pdi1; + unsigned int rx_alignment; + unsigned int tx_alignment; + unsigned int num_frames_; unsigned int num_frames; + unsigned int fake_size; + unsigned int tx_pad; + unsigned int rx_pad; int command; int ret1; int ret; int dir; + int len; int i; stream = sdw_alloc_stream("BPT", SDW_STREAM_BPT); @@ -138,23 +152,77 @@ static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave * command = (msg->flags & SDW_MSG_FLAG_WRITE) ? 0 : 1; - ret = sdw_cdns_bpt_find_buffer_sizes(command, cdns->bus.params.row, cdns->bus.params.col, - msg->len, SDW_BPT_MSG_MAX_BYTES, &data_per_frame, - &pdi0_buffer_size, &pdi1_buffer_size, &num_frames); + ret = sdw_cdns_bpt_find_bandwidth(command, cdns->bus.params.row, + cdns->bus.params.col, + prop->default_frame_rate, + &tx_dma_bandwidth, &rx_dma_bandwidth); if (ret < 0) goto deprepare_stream; + len = 0; + pdi0_buffer_size = 0; + pdi1_buffer_size = 0; + num_frames = 0; + /* Add up pdi buffer size and frame numbers of each BPT sections */ + for (i = 0; i < msg->sections; i++) { + ret = sdw_cdns_bpt_find_buffer_sizes(command, cdns->bus.params.row, + cdns->bus.params.col, + msg->sec[i].len, SDW_BPT_MSG_MAX_BYTES, + &data_per_frame, &pdi0_buffer_size_, + &pdi1_buffer_size_, &num_frames_); + if (ret < 0) + goto deprepare_stream; + + len += msg->sec[i].len; + pdi0_buffer_size += pdi0_buffer_size_; + pdi1_buffer_size += pdi1_buffer_size_; + num_frames += num_frames_; + } + sdw->bpt_ctx.pdi0_buffer_size = pdi0_buffer_size; sdw->bpt_ctx.pdi1_buffer_size = pdi1_buffer_size; sdw->bpt_ctx.num_frames = num_frames; sdw->bpt_ctx.data_per_frame = data_per_frame; - tx_dma_bandwidth = div_u64((u64)pdi0_buffer_size * 8 * (u64)prop->default_frame_rate, - num_frames); - rx_dma_bandwidth = div_u64((u64)pdi1_buffer_size * 8 * (u64)prop->default_frame_rate, - num_frames); + + rx_alignment = hda_sdw_bpt_get_buf_size_alignment(rx_dma_bandwidth); + tx_alignment = hda_sdw_bpt_get_buf_size_alignment(tx_dma_bandwidth); + + if (command) { /* read */ + /* Get buffer size of a full frame */ + ret = sdw_cdns_bpt_find_buffer_sizes(command, cdns->bus.params.row, + cdns->bus.params.col, + data_per_frame, SDW_BPT_MSG_MAX_BYTES, + &data_per_frame, &pdi0_buf_size_pre_frame, + &pdi1_buf_size_pre_frame, &fake_num_frames); + if (ret < 0) + goto deprepare_stream; + + /* find fake pdi1 buffer size */ + rx_pad = rx_alignment - (pdi1_buffer_size % rx_alignment); + while (rx_pad <= READ_PDI1_MIN_SIZE) + rx_pad += rx_alignment; + + pdi1_buffer_size += rx_pad; + /* It is fine if we request more than enough byte to read */ + fake_num_frames = DIV_ROUND_UP(rx_pad, pdi1_buf_size_pre_frame); + fake_size = fake_num_frames * data_per_frame; + + /* find fake pdi0 buffer size */ + pdi0_buffer_size += (fake_num_frames * pdi0_buf_size_pre_frame); + tx_pad = tx_alignment - (pdi0_buffer_size % tx_alignment); + pdi0_buffer_size += tx_pad; + } else { /* write */ + /* + * For the write command, the rx data block is 4, and the rx buffer size of a frame + * is 8. So the rx buffer size (pdi0_buffer_size) is always a multiple of rx + * alignment. + */ + tx_pad = tx_alignment - (pdi0_buffer_size % tx_alignment); + pdi0_buffer_size += tx_pad; + } dev_dbg(cdns->dev, "Message len %d transferred in %d frames (%d per frame)\n", - msg->len, num_frames, data_per_frame); + len, num_frames, data_per_frame); dev_dbg(cdns->dev, "sizes pdi0 %d pdi1 %d tx_bandwidth %d rx_bandwidth %d\n", pdi0_buffer_size, pdi1_buffer_size, tx_dma_bandwidth, rx_dma_bandwidth); @@ -169,15 +237,16 @@ static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave * } if (!command) { - ret = sdw_cdns_prepare_write_dma_buffer(msg->dev_num, msg->addr, msg->buf, - msg->len, data_per_frame, + ret = sdw_cdns_prepare_write_dma_buffer(msg->dev_num, msg->sec, msg->sections, + data_per_frame, sdw->bpt_ctx.dmab_tx_bdl.area, pdi0_buffer_size, &tx_total_bytes); } else { - ret = sdw_cdns_prepare_read_dma_buffer(msg->dev_num, msg->addr, msg->len, + ret = sdw_cdns_prepare_read_dma_buffer(msg->dev_num, msg->sec, msg->sections, data_per_frame, sdw->bpt_ctx.dmab_tx_bdl.area, - pdi0_buffer_size, &tx_total_bytes); + pdi0_buffer_size, &tx_total_bytes, + fake_size); } if (!ret) @@ -252,11 +321,16 @@ static int intel_ace2x_bpt_send_async(struct sdw_intel *sdw, struct sdw_slave *s struct sdw_bpt_msg *msg) { struct sdw_cdns *cdns = &sdw->cdns; + int len = 0; int ret; + int i; + + for (i = 0; i < msg->sections; i++) + len += msg->sec[i].len; - if (msg->len < INTEL_BPT_MSG_BYTE_MIN) { + if (len < INTEL_BPT_MSG_BYTE_MIN) { dev_err(cdns->dev, "BPT message length %d is less than the minimum bytes %d\n", - msg->len, INTEL_BPT_MSG_BYTE_MIN); + len, INTEL_BPT_MSG_BYTE_MIN); return -EINVAL; } @@ -316,7 +390,7 @@ static int intel_ace2x_bpt_wait(struct sdw_intel *sdw, struct sdw_slave *slave, } else { ret = sdw_cdns_check_read_response(cdns->dev, sdw->bpt_ctx.dmab_rx_bdl.area, sdw->bpt_ctx.pdi1_buffer_size, - msg->buf, msg->len, sdw->bpt_ctx.num_frames, + msg->sec, msg->sections, sdw->bpt_ctx.num_frames, sdw->bpt_ctx.data_per_frame); if (ret < 0) dev_err(cdns->dev, "%s: BPT Read failed %d\n", __func__, ret); diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index 5b3078220189..17afc5aa8b44 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -31,6 +31,7 @@ #define SWRM_VERSION_1_5_1 0x01050001 #define SWRM_VERSION_1_7_0 0x01070000 #define SWRM_VERSION_2_0_0 0x02000000 +#define SWRM_VERSION_3_1_0 0x03010000 #define SWRM_COMP_HW_VERSION 0x00 #define SWRM_COMP_CFG_ADDR 0x04 #define SWRM_COMP_CFG_IRQ_LEVEL_OR_PULSE_MSK BIT(1) @@ -40,6 +41,9 @@ #define SWRM_COMP_PARAMS_RD_FIFO_DEPTH GENMASK(19, 15) #define SWRM_COMP_PARAMS_DOUT_PORTS_MASK GENMASK(4, 0) #define SWRM_COMP_PARAMS_DIN_PORTS_MASK GENMASK(9, 5) +#define SWRM_V3_COMP_PARAMS_WR_FIFO_DEPTH GENMASK(17, 10) +#define SWRM_V3_COMP_PARAMS_RD_FIFO_DEPTH GENMASK(23, 18) + #define SWRM_COMP_MASTER_ID 0x104 #define SWRM_V1_3_INTERRUPT_STATUS 0x200 #define SWRM_V2_0_INTERRUPT_STATUS 0x5000 @@ -99,14 +103,15 @@ #define SWRM_MCP_SLV_STATUS 0x1090 #define SWRM_MCP_SLV_STATUS_MASK GENMASK(1, 0) #define SWRM_MCP_SLV_STATUS_SZ 2 -#define SWRM_DP_PORT_CTRL_BANK(n, m) (0x1124 + 0x100 * (n - 1) + 0x40 * m) -#define SWRM_DP_PORT_CTRL_2_BANK(n, m) (0x1128 + 0x100 * (n - 1) + 0x40 * m) -#define SWRM_DP_BLOCK_CTRL_1(n) (0x112C + 0x100 * (n - 1)) -#define SWRM_DP_BLOCK_CTRL2_BANK(n, m) (0x1130 + 0x100 * (n - 1) + 0x40 * m) -#define SWRM_DP_PORT_HCTRL_BANK(n, m) (0x1134 + 0x100 * (n - 1) + 0x40 * m) -#define SWRM_DP_BLOCK_CTRL3_BANK(n, m) (0x1138 + 0x100 * (n - 1) + 0x40 * m) -#define SWRM_DP_SAMPLECTRL2_BANK(n, m) (0x113C + 0x100 * (n - 1) + 0x40 * m) -#define SWRM_DIN_DPn_PCM_PORT_CTRL(n) (0x1054 + 0x100 * (n - 1)) + +#define SWRM_DPn_PORT_CTRL_BANK(offset, n, m) (offset + 0x100 * (n - 1) + 0x40 * m) +#define SWRM_DPn_PORT_CTRL_2_BANK(offset, n, m) (offset + 0x100 * (n - 1) + 0x40 * m) +#define SWRM_DPn_BLOCK_CTRL_1(offset, n) (offset + 0x100 * (n - 1)) +#define SWRM_DPn_BLOCK_CTRL2_BANK(offset, n, m) (offset + 0x100 * (n - 1) + 0x40 * m) +#define SWRM_DPn_PORT_HCTRL_BANK(offset, n, m) (offset + 0x100 * (n - 1) + 0x40 * m) +#define SWRM_DPn_BLOCK_CTRL3_BANK(offset, n, m) (offset + 0x100 * (n - 1) + 0x40 * m) +#define SWRM_DPn_SAMPLECTRL2_BANK(offset, n, m) (offset + 0x100 * (n - 1) + 0x40 * m) + #define SWR_V1_3_MSTR_MAX_REG_ADDR 0x1740 #define SWR_V2_0_MSTR_MAX_REG_ADDR 0x50ac @@ -128,7 +133,6 @@ #define MAX_FREQ_NUM 1 #define TIMEOUT_MS 100 #define QCOM_SWRM_MAX_RD_LEN 0x1 -#define QCOM_SDW_MAX_PORTS 14 #define DEFAULT_CLK_FREQ 9600000 #define SWRM_MAX_DAIS 0xF #define SWR_INVALID_PARAM 0xFF @@ -172,6 +176,13 @@ enum { SWRM_REG_CMD_FIFO_RD_CMD, SWRM_REG_CMD_FIFO_STATUS, SWRM_REG_CMD_FIFO_RD_FIFO_ADDR, + SWRM_OFFSET_DP_PORT_CTRL_BANK, + SWRM_OFFSET_DP_PORT_CTRL_2_BANK, + SWRM_OFFSET_DP_BLOCK_CTRL_1, + SWRM_OFFSET_DP_BLOCK_CTRL2_BANK, + SWRM_OFFSET_DP_PORT_HCTRL_BANK, + SWRM_OFFSET_DP_BLOCK_CTRL3_BANK, + SWRM_OFFSET_DP_SAMPLECTRL2_BANK, }; struct qcom_swrm_ctrl { @@ -195,6 +206,7 @@ struct qcom_swrm_ctrl { int wake_irq; int num_din_ports; int num_dout_ports; + int nports; int cols_index; int rows_index; unsigned long port_mask; @@ -202,14 +214,13 @@ struct qcom_swrm_ctrl { u8 rcmd_id; u8 wcmd_id; /* Port numbers are 1 - 14 */ - struct qcom_swrm_port_config pconfig[QCOM_SDW_MAX_PORTS + 1]; + struct qcom_swrm_port_config *pconfig; struct sdw_stream_runtime *sruntime[SWRM_MAX_DAIS]; 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; u32 wr_fifo_depth; - u32 rd_fifo_depth; bool clock_stop_not_supported; }; @@ -231,6 +242,13 @@ static const unsigned int swrm_v1_3_reg_layout[] = { [SWRM_REG_CMD_FIFO_RD_CMD] = SWRM_V1_3_CMD_FIFO_RD_CMD, [SWRM_REG_CMD_FIFO_STATUS] = SWRM_V1_3_CMD_FIFO_STATUS, [SWRM_REG_CMD_FIFO_RD_FIFO_ADDR] = SWRM_V1_3_CMD_FIFO_RD_FIFO_ADDR, + [SWRM_OFFSET_DP_PORT_CTRL_BANK] = 0x1124, + [SWRM_OFFSET_DP_PORT_CTRL_2_BANK] = 0x1128, + [SWRM_OFFSET_DP_BLOCK_CTRL_1] = 0x112c, + [SWRM_OFFSET_DP_BLOCK_CTRL2_BANK] = 0x1130, + [SWRM_OFFSET_DP_PORT_HCTRL_BANK] = 0x1134, + [SWRM_OFFSET_DP_BLOCK_CTRL3_BANK] = 0x1138, + [SWRM_OFFSET_DP_SAMPLECTRL2_BANK] = 0x113c, }; static const struct qcom_swrm_data swrm_v1_3_data = { @@ -265,6 +283,13 @@ static const unsigned int swrm_v2_0_reg_layout[] = { [SWRM_REG_CMD_FIFO_RD_CMD] = SWRM_V2_0_CMD_FIFO_RD_CMD, [SWRM_REG_CMD_FIFO_STATUS] = SWRM_V2_0_CMD_FIFO_STATUS, [SWRM_REG_CMD_FIFO_RD_FIFO_ADDR] = SWRM_V2_0_CMD_FIFO_RD_FIFO_ADDR, + [SWRM_OFFSET_DP_PORT_CTRL_BANK] = 0x1124, + [SWRM_OFFSET_DP_PORT_CTRL_2_BANK] = 0x1128, + [SWRM_OFFSET_DP_BLOCK_CTRL_1] = 0x112c, + [SWRM_OFFSET_DP_BLOCK_CTRL2_BANK] = 0x1130, + [SWRM_OFFSET_DP_PORT_HCTRL_BANK] = 0x1134, + [SWRM_OFFSET_DP_BLOCK_CTRL3_BANK] = 0x1138, + [SWRM_OFFSET_DP_SAMPLECTRL2_BANK] = 0x113c, }; static const struct qcom_swrm_data swrm_v2_0_data = { @@ -275,6 +300,32 @@ static const struct qcom_swrm_data swrm_v2_0_data = { .reg_layout = swrm_v2_0_reg_layout, }; +static const unsigned int swrm_v3_0_reg_layout[] = { + [SWRM_REG_FRAME_GEN_ENABLED] = SWRM_V2_0_LINK_STATUS, + [SWRM_REG_INTERRUPT_STATUS] = SWRM_V2_0_INTERRUPT_STATUS, + [SWRM_REG_INTERRUPT_MASK_ADDR] = 0, /* Not present */ + [SWRM_REG_INTERRUPT_CLEAR] = SWRM_V2_0_INTERRUPT_CLEAR, + [SWRM_REG_INTERRUPT_CPU_EN] = SWRM_V2_0_INTERRUPT_CPU_EN, + [SWRM_REG_CMD_FIFO_WR_CMD] = SWRM_V2_0_CMD_FIFO_WR_CMD, + [SWRM_REG_CMD_FIFO_RD_CMD] = SWRM_V2_0_CMD_FIFO_RD_CMD, + [SWRM_REG_CMD_FIFO_STATUS] = SWRM_V2_0_CMD_FIFO_STATUS, + [SWRM_REG_CMD_FIFO_RD_FIFO_ADDR] = SWRM_V2_0_CMD_FIFO_RD_FIFO_ADDR, + [SWRM_OFFSET_DP_PORT_CTRL_BANK] = 0x1224, + [SWRM_OFFSET_DP_PORT_CTRL_2_BANK] = 0x1228, + [SWRM_OFFSET_DP_BLOCK_CTRL_1] = 0x122c, + [SWRM_OFFSET_DP_BLOCK_CTRL2_BANK] = 0x1230, + [SWRM_OFFSET_DP_PORT_HCTRL_BANK] = 0x1234, + [SWRM_OFFSET_DP_BLOCK_CTRL3_BANK] = 0x1238, + [SWRM_OFFSET_DP_SAMPLECTRL2_BANK] = 0x123c, +}; + +static const struct qcom_swrm_data swrm_v3_0_data = { + .default_rows = 50, + .default_cols = 16, + .sw_clk_gate_required = true, + .max_reg = SWR_V2_0_MSTR_MAX_REG_ADDR, + .reg_layout = swrm_v3_0_reg_layout, +}; #define to_qcom_sdw(b) container_of(b, struct qcom_swrm_ctrl, bus) static int qcom_swrm_ahb_reg_read(struct qcom_swrm_ctrl *ctrl, int reg, @@ -898,8 +949,11 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl) swrm_wait_for_frame_gen_enabled(ctrl); ctrl->slave_status = 0; ctrl->reg_read(ctrl, SWRM_COMP_PARAMS, &val); - ctrl->rd_fifo_depth = FIELD_GET(SWRM_COMP_PARAMS_RD_FIFO_DEPTH, val); - ctrl->wr_fifo_depth = FIELD_GET(SWRM_COMP_PARAMS_WR_FIFO_DEPTH, val); + + if (ctrl->version >= SWRM_VERSION_3_1_0) + ctrl->wr_fifo_depth = FIELD_GET(SWRM_V3_COMP_PARAMS_WR_FIFO_DEPTH, val); + else + ctrl->wr_fifo_depth = FIELD_GET(SWRM_COMP_PARAMS_WR_FIFO_DEPTH, val); return 0; } @@ -966,10 +1020,10 @@ static int qcom_swrm_port_params(struct sdw_bus *bus, unsigned int bank) { struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus); + u32 offset = ctrl->reg_layout[SWRM_OFFSET_DP_BLOCK_CTRL_1]; - return ctrl->reg_write(ctrl, SWRM_DP_BLOCK_CTRL_1(p_params->num), - p_params->bps - 1); - + return ctrl->reg_write(ctrl, SWRM_DPn_BLOCK_CTRL_1(offset, p_params->num), + p_params->bps - 1); } static int qcom_swrm_transport_params(struct sdw_bus *bus, @@ -979,9 +1033,11 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus, struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus); struct qcom_swrm_port_config *pcfg; u32 value; - int reg = SWRM_DP_PORT_CTRL_BANK((params->port_num), bank); + int reg, offset = ctrl->reg_layout[SWRM_OFFSET_DP_PORT_CTRL_BANK]; int ret; + reg = SWRM_DPn_PORT_CTRL_BANK(offset, params->port_num, bank); + pcfg = &ctrl->pconfig[params->port_num]; value = pcfg->off1 << SWRM_DP_PORT_CTRL_OFFSET1_SHFT; @@ -993,15 +1049,19 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus, goto err; if (pcfg->si > 0xff) { + offset = ctrl->reg_layout[SWRM_OFFSET_DP_SAMPLECTRL2_BANK]; value = (pcfg->si >> 8) & 0xff; - reg = SWRM_DP_SAMPLECTRL2_BANK(params->port_num, bank); + reg = SWRM_DPn_SAMPLECTRL2_BANK(offset, params->port_num, bank); + ret = ctrl->reg_write(ctrl, reg, value); if (ret) goto err; } if (pcfg->lane_control != SWR_INVALID_PARAM) { - reg = SWRM_DP_PORT_CTRL_2_BANK(params->port_num, bank); + offset = ctrl->reg_layout[SWRM_OFFSET_DP_PORT_CTRL_2_BANK]; + reg = SWRM_DPn_PORT_CTRL_2_BANK(offset, params->port_num, bank); + value = pcfg->lane_control; ret = ctrl->reg_write(ctrl, reg, value); if (ret) @@ -1009,20 +1069,23 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus, } if (pcfg->blk_group_count != SWR_INVALID_PARAM) { - reg = SWRM_DP_BLOCK_CTRL2_BANK(params->port_num, bank); + offset = ctrl->reg_layout[SWRM_OFFSET_DP_BLOCK_CTRL2_BANK]; + + reg = SWRM_DPn_BLOCK_CTRL2_BANK(offset, params->port_num, bank); + value = pcfg->blk_group_count; ret = ctrl->reg_write(ctrl, reg, value); if (ret) goto err; } - if (pcfg->hstart != SWR_INVALID_PARAM - && pcfg->hstop != SWR_INVALID_PARAM) { - reg = SWRM_DP_PORT_HCTRL_BANK(params->port_num, bank); + offset = ctrl->reg_layout[SWRM_OFFSET_DP_PORT_HCTRL_BANK]; + reg = SWRM_DPn_PORT_HCTRL_BANK(offset, params->port_num, bank); + + if (pcfg->hstart != SWR_INVALID_PARAM && pcfg->hstop != SWR_INVALID_PARAM) { value = (pcfg->hstop << 4) | pcfg->hstart; ret = ctrl->reg_write(ctrl, reg, value); } else { - reg = SWRM_DP_PORT_HCTRL_BANK(params->port_num, bank); value = (SWR_HSTOP_MAX_VAL << 4) | SWR_HSTART_MIN_VAL; ret = ctrl->reg_write(ctrl, reg, value); } @@ -1031,7 +1094,8 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus, goto err; if (pcfg->bp_mode != SWR_INVALID_PARAM) { - reg = SWRM_DP_BLOCK_CTRL3_BANK(params->port_num, bank); + offset = ctrl->reg_layout[SWRM_OFFSET_DP_BLOCK_CTRL3_BANK]; + reg = SWRM_DPn_BLOCK_CTRL3_BANK(offset, params->port_num, bank); ret = ctrl->reg_write(ctrl, reg, pcfg->bp_mode); } @@ -1043,9 +1107,12 @@ static int qcom_swrm_port_enable(struct sdw_bus *bus, struct sdw_enable_ch *enable_ch, unsigned int bank) { - u32 reg = SWRM_DP_PORT_CTRL_BANK(enable_ch->port_num, bank); + u32 reg; struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus); u32 val; + u32 offset = ctrl->reg_layout[SWRM_OFFSET_DP_PORT_CTRL_BANK]; + + reg = SWRM_DPn_PORT_CTRL_BANK(offset, enable_ch->port_num, bank); ctrl->reg_read(ctrl, reg, &val); @@ -1155,7 +1222,6 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl, struct snd_pcm_hw_params *params, int direction) { - struct sdw_port_config pconfig[QCOM_SDW_MAX_PORTS]; struct sdw_stream_config sconfig; struct sdw_master_runtime *m_rt; struct sdw_slave_runtime *s_rt; @@ -1164,6 +1230,10 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl, unsigned long *port_mask; int maxport, pn, nports = 0, ret = 0; unsigned int m_port; + struct sdw_port_config *pconfig __free(kfree) = kcalloc(ctrl->nports, + sizeof(*pconfig), GFP_KERNEL); + if (!pconfig) + return -ENOMEM; if (direction == SNDRV_PCM_STREAM_CAPTURE) sconfig.direction = SDW_DATA_DIR_TX; @@ -1188,8 +1258,7 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl, continue; port_mask = &ctrl->port_mask; - maxport = ctrl->num_dout_ports + ctrl->num_din_ports; - + maxport = ctrl->nports; list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) { slave = s_rt->slave; @@ -1349,17 +1418,8 @@ static int qcom_swrm_register_dais(struct qcom_swrm_ctrl *ctrl) static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl) { struct device_node *np = ctrl->dev->of_node; - u8 off1[QCOM_SDW_MAX_PORTS]; - u8 off2[QCOM_SDW_MAX_PORTS]; - u16 si[QCOM_SDW_MAX_PORTS]; - u8 bp_mode[QCOM_SDW_MAX_PORTS] = { 0, }; - u8 hstart[QCOM_SDW_MAX_PORTS]; - u8 hstop[QCOM_SDW_MAX_PORTS]; - u8 word_length[QCOM_SDW_MAX_PORTS]; - u8 blk_group_count[QCOM_SDW_MAX_PORTS]; - u8 lane_control[QCOM_SDW_MAX_PORTS]; - int i, ret, nports, val; - bool si_16 = false; + struct qcom_swrm_port_config *pcfg; + int i, ret, val; ctrl->reg_read(ctrl, SWRM_COMP_PARAMS, &val); @@ -1367,88 +1427,78 @@ static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl) ctrl->num_din_ports = FIELD_GET(SWRM_COMP_PARAMS_DIN_PORTS_MASK, val); ret = of_property_read_u32(np, "qcom,din-ports", &val); - if (ret) - return ret; - - if (val > ctrl->num_din_ports) - return -EINVAL; + if (!ret) { /* only if present */ + if (val != ctrl->num_din_ports) { + dev_err(ctrl->dev, "din-ports (%d) mismatch with controller (%d)", + val, ctrl->num_din_ports); + } - ctrl->num_din_ports = val; + ctrl->num_din_ports = val; + } ret = of_property_read_u32(np, "qcom,dout-ports", &val); - if (ret) - return ret; + if (!ret) { /* only if present */ + if (val != ctrl->num_dout_ports) { + dev_err(ctrl->dev, "dout-ports (%d) mismatch with controller (%d)", + val, ctrl->num_dout_ports); + } - if (val > ctrl->num_dout_ports) - return -EINVAL; + ctrl->num_dout_ports = val; + } - ctrl->num_dout_ports = val; + ctrl->nports = ctrl->num_dout_ports + ctrl->num_din_ports; - nports = ctrl->num_dout_ports + ctrl->num_din_ports; - if (nports > QCOM_SDW_MAX_PORTS) - return -EINVAL; + ctrl->pconfig = devm_kcalloc(ctrl->dev, ctrl->nports + 1, + sizeof(*ctrl->pconfig), GFP_KERNEL); + if (!ctrl->pconfig) + return -ENOMEM; - /* Valid port numbers are from 1-14, so mask out port 0 explicitly */ set_bit(0, &ctrl->port_mask); + /* Valid port numbers are from 1, so mask out port 0 explicitly */ + for (i = 0; i < ctrl->nports; i++) { + pcfg = &ctrl->pconfig[i + 1]; - ret = of_property_read_u8_array(np, "qcom,ports-offset1", - off1, nports); - if (ret) - return ret; - - ret = of_property_read_u8_array(np, "qcom,ports-offset2", - off2, nports); - if (ret) - return ret; - - ret = of_property_read_u8_array(np, "qcom,ports-sinterval-low", - (u8 *)si, nports); - if (ret) { - ret = of_property_read_u16_array(np, "qcom,ports-sinterval", - si, nports); + ret = of_property_read_u8_index(np, "qcom,ports-offset1", i, &pcfg->off1); if (ret) return ret; - si_16 = true; - } - ret = of_property_read_u8_array(np, "qcom,ports-block-pack-mode", - bp_mode, nports); - if (ret) { - if (ctrl->version <= SWRM_VERSION_1_3_0) - memset(bp_mode, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); - else + ret = of_property_read_u8_index(np, "qcom,ports-offset2", i, &pcfg->off2); + if (ret) return ret; - } - memset(hstart, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); - of_property_read_u8_array(np, "qcom,ports-hstart", hstart, nports); + ret = of_property_read_u8_index(np, "qcom,ports-sinterval-low", i, (u8 *)&pcfg->si); + if (ret) { + ret = of_property_read_u16_index(np, "qcom,ports-sinterval", i, &pcfg->si); + if (ret) + return ret; + } + + ret = of_property_read_u8_index(np, "qcom,ports-block-pack-mode", + i, &pcfg->bp_mode); + if (ret) { + if (ctrl->version <= SWRM_VERSION_1_3_0) + pcfg->bp_mode = SWR_INVALID_PARAM; + else + return ret; + } + + /* Optional properties */ + pcfg->hstart = SWR_INVALID_PARAM; + pcfg->hstop = SWR_INVALID_PARAM; + pcfg->word_length = SWR_INVALID_PARAM; + pcfg->blk_group_count = SWR_INVALID_PARAM; + pcfg->lane_control = SWR_INVALID_PARAM; - memset(hstop, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); - of_property_read_u8_array(np, "qcom,ports-hstop", hstop, nports); + of_property_read_u8_index(np, "qcom,ports-hstart", i, &pcfg->hstart); - memset(word_length, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); - of_property_read_u8_array(np, "qcom,ports-word-length", word_length, nports); + of_property_read_u8_index(np, "qcom,ports-hstop", i, &pcfg->hstop); - memset(blk_group_count, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); - of_property_read_u8_array(np, "qcom,ports-block-group-count", blk_group_count, nports); + of_property_read_u8_index(np, "qcom,ports-word-length", i, &pcfg->word_length); - memset(lane_control, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); - of_property_read_u8_array(np, "qcom,ports-lane-control", lane_control, nports); + of_property_read_u8_index(np, "qcom,ports-block-group-count", + i, &pcfg->blk_group_count); - for (i = 0; i < nports; i++) { - /* Valid port number range is from 1-14 */ - if (si_16) - ctrl->pconfig[i + 1].si = si[i]; - else - ctrl->pconfig[i + 1].si = ((u8 *)si)[i]; - ctrl->pconfig[i + 1].off1 = off1[i]; - ctrl->pconfig[i + 1].off2 = off2[i]; - ctrl->pconfig[i + 1].bp_mode = bp_mode[i]; - ctrl->pconfig[i + 1].hstart = hstart[i]; - ctrl->pconfig[i + 1].hstop = hstop[i]; - ctrl->pconfig[i + 1].word_length = word_length[i]; - ctrl->pconfig[i + 1].blk_group_count = blk_group_count[i]; - ctrl->pconfig[i + 1].lane_control = lane_control[i]; + of_property_read_u8_index(np, "qcom,ports-lane-control", i, &pcfg->lane_control); } return 0; @@ -1769,6 +1819,7 @@ static const struct of_device_id qcom_swrm_of_match[] = { { .compatible = "qcom,soundwire-v1.6.0", .data = &swrm_v1_6_data }, { .compatible = "qcom,soundwire-v1.7.0", .data = &swrm_v1_5_data }, { .compatible = "qcom,soundwire-v2.0.0", .data = &swrm_v2_0_data }, + { .compatible = "qcom,soundwire-v3.1.0", .data = &swrm_v3_0_data }, {/* sentinel */}, }; |
